diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 44b6140423..0b4d57e9cb 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -116,7 +116,7 @@ jobs: rustup default nightly rustup component add rustfmt rust-src rustup target add wasm32-unknown-unknown - cargo install -f wasm-bindgen-cli + cargo install -f wasm-bindgen-cli --version 0.2.93 - name: Setup Rust Cache uses: Swatinem/rust-cache@v2 diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 35eb1ddfbb..c4f6642370 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -2,5 +2,6 @@ + \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b0e9e7614..ab72a6c775 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.10.0] - 2024-10-10 + +### Added + +- GraphQL endpoints for o1js. +- Support for batched verification of proofs. +- Enabled full proof verification of completed works included in blocks. + +### Changed + +- Deduplication of zkApp logic. +- Various internal improvements. + +### Fixed + +- Regression in the verification zkApp transactions with feature flags (introduced when upgrading proof-systems). +- Potential overflow in yamux. +- Added a missing check for next epoch seed finality + ## [0.9.0] - 2024-10-02 ### Fixes @@ -260,7 +279,8 @@ First public release. - Alpha version of the node which can connect and syncup to the berkeleynet network, and keep applying new blocks to maintain consensus state and ledger up to date. - Web-based frontend for the node. -[Unreleased]: https://github.com/openmina/openmina/compare/v0.9.0...develop +[Unreleased]: https://github.com/openmina/openmina/compare/v0.10.0...develop +[0.10.0]: https://github.com/openmina/openmina/releases/tag/v0.9.0...v0.10.0 [0.9.0]: https://github.com/openmina/openmina/releases/tag/v0.8.14...v0.9.0 [0.8.14]: https://github.com/openmina/openmina/releases/tag/v0.8.13...v0.8.14 [0.8.13]: https://github.com/openmina/openmina/releases/tag/v0.8.3...v0.8.13 diff --git a/Cargo.lock b/Cargo.lock index dab9bd171f..1bc2815932 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -93,7 +93,7 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom 0.2.15", + "getrandom", "once_cell", "version_check", ] @@ -105,7 +105,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42cd52102d3df161c77a887b608d7a4897d7cc112886a9537b738a887a03aaff" dependencies = [ "cfg-if", - "getrandom 0.2.15", + "getrandom", "once_cell", "version_check", "zerocopy", @@ -331,7 +331,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" dependencies = [ "num-traits", - "rand 0.8.5", + "rand", "rayon", ] @@ -530,6 +530,18 @@ dependencies = [ "winapi", ] +[[package]] +name = "auto_enums" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "459b77b7e855f875fd15f101064825cd79eb83185a961d66e6298560126facfb" +dependencies = [ + "derive_utils", + "proc-macro2", + "quote", + "syn 2.0.58", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -797,23 +809,6 @@ dependencies = [ "tinyvec", ] -[[package]] -name = "bson" -version = "1.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0aa578035b938855a710ba58d43cfb4d435f3619f99236fb35922a574d6cb1" -dependencies = [ - "base64 0.13.1", - "chrono", - "hex", - "lazy_static", - "linked-hash-map", - "rand 0.7.3", - "serde", - "serde_json", - "uuid 0.8.2", -] - [[package]] name = "bumpalo" version = "3.14.0" @@ -929,10 +924,8 @@ checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a" dependencies = [ "android-tzdata", "iana-time-zone", - "js-sys", "num-traits", "serde", - "wasm-bindgen", "windows-targets 0.52.0", ] @@ -1013,7 +1006,7 @@ checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "cli" -version = "0.9.0" +version = "0.10.0" dependencies = [ "anyhow", "bytes", @@ -1030,7 +1023,7 @@ dependencies = [ "openmina-core", "openmina-node-account", "openmina-node-native", - "rand 0.8.5", + "rand", "rayon", "redux", "reqwest", @@ -1240,7 +1233,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array", - "rand_core 0.6.4", + "rand_core", "serdect", "subtle", "zeroize", @@ -1253,7 +1246,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", - "rand_core 0.6.4", + "rand_core", "typenum", ] @@ -1571,13 +1564,13 @@ dependencies = [ [[package]] name = "derive_utils" -version = "0.11.2" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "532b4c15dccee12c7044f1fcad956e98410860b22231e44a3b827464797ca7bf" +checksum = "65f152f4b8559c4da5d574bafc7af85454d706b4c5fe8b530d508cacbb6807ea" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.58", ] [[package]] @@ -1715,7 +1708,7 @@ checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" dependencies = [ "curve25519-dalek", "ed25519", - "rand_core 0.6.4", + "rand_core", "serde", "sha2 0.10.8", "subtle", @@ -1746,7 +1739,7 @@ dependencies = [ "hkdf", "pem-rfc7468", "pkcs8", - "rand_core 0.6.4", + "rand_core", "sec1", "subtle", "zeroize", @@ -1895,7 +1888,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -2036,17 +2029,6 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" -[[package]] -name = "futures-enum" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3422d14de7903a52e9dbc10ae05a7e14445ec61890100e098754e120b2bd7b1e" -dependencies = [ - "derive_utils", - "quote", - "syn 1.0.109", -] - [[package]] name = "futures-executor" version = "0.3.30" @@ -2232,17 +2214,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.15" @@ -2252,7 +2223,7 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] @@ -2316,16 +2287,6 @@ dependencies = [ "serde", ] -[[package]] -name = "graphql-parser" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1abd4ce5247dfc04a03ccde70f87a048458c9356c7e41d21ad8c407b3dde6f2" -dependencies = [ - "combine", - "thiserror", -] - [[package]] name = "graphql-parser" version = "0.4.0" @@ -2355,7 +2316,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e27ed0c2cf0c0cc52c6bcf3b45c907f433015e580879d14005386251842fb0a" dependencies = [ "graphql-introspection-query", - "graphql-parser 0.4.0", + "graphql-parser", "heck 0.4.1", "lazy_static", "proc-macro2", @@ -2383,7 +2344,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -2394,7 +2355,7 @@ source = "git+https://github.com/openmina/proof-systems?rev=2fdb5a7#2fdb5a75c61e dependencies = [ "ark-ec", "ark-ff", - "rand 0.8.5", + "rand", ] [[package]] @@ -2418,7 +2379,7 @@ dependencies = [ [[package]] name = "hash-tool" -version = "0.9.0" +version = "0.10.0" dependencies = [ "bs58 0.5.0", "hex", @@ -2762,7 +2723,7 @@ dependencies = [ "http", "hyper", "log", - "rand 0.8.5", + "rand", "tokio", "url", "xmltree", @@ -2818,7 +2779,7 @@ dependencies = [ "bytes", "log", "portable-atomic", - "rand 0.8.5", + "rand", "rtcp", "rtp", "thiserror", @@ -2921,46 +2882,40 @@ dependencies = [ [[package]] name = "juniper" -version = "0.15.11" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52adf17d43d0b526eed31fac15d9312941c5c2558ffbfb105811690b96d6e2f1" +checksum = "943306315b1a7a03d27af9dfb0c288d9f4da8830c17df4bceb7d50a47da0982c" dependencies = [ "async-trait", - "bson", - "chrono", + "auto_enums", "fnv", "futures", - "futures-enum", - "graphql-parser 0.3.0", - "indexmap 1.9.3", + "indexmap 2.0.2", "juniper_codegen", "serde", "smartstring", "static_assertions", - "url", - "uuid 0.8.2", ] [[package]] name = "juniper_codegen" -version = "0.15.9" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aee97671061ad50301ba077d054d295e01d31a1868fbd07902db651f987e71db" +checksum = "760dbe46660494d469023d661e8d268f413b2cb68c999975dcc237407096a693" dependencies = [ - "proc-macro-error", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.58", + "url", ] [[package]] name = "juniper_warp" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d167107f6634c92f90daae1a298133377373e935d455042f90efc480fae4a52" +checksum = "3388baae40c95f5bc426b4874620e5f429743a9b82b8d574d32ee6f36c24963f" dependencies = [ - "anyhow", - "futures", + "headers", "juniper", "serde", "serde_json", @@ -3002,8 +2957,8 @@ dependencies = [ "o1-utils", "once_cell", "poly-commitment", - "rand 0.8.5", - "rand_core 0.6.4", + "rand", + "rand_core", "rayon", "rmp-serde", "serde", @@ -3025,7 +2980,7 @@ dependencies = [ [[package]] name = "ledger-tool" -version = "0.9.0" +version = "0.10.0" dependencies = [ "anyhow", "mina-curves", @@ -3060,7 +3015,7 @@ dependencies = [ "either", "futures", "futures-timer", - "getrandom 0.2.15", + "getrandom", "instant", "libp2p-allow-block-list", "libp2p-connection-limits", @@ -3126,7 +3081,7 @@ dependencies = [ "parking_lot 0.12.1", "pin-project", "quick-protobuf", - "rand 0.8.5", + "rand", "rw-stream-sink", "serde", "smallvec", @@ -3163,7 +3118,7 @@ dependencies = [ "fnv", "futures", "futures-ticker", - "getrandom 0.2.15", + "getrandom", "hex_fmt", "instant", "libp2p-core", @@ -3173,7 +3128,7 @@ dependencies = [ "prometheus-client", "quick-protobuf", "quick-protobuf-codec", - "rand 0.8.5", + "rand", "regex", "serde", "sha2 0.10.8", @@ -3216,7 +3171,7 @@ dependencies = [ "log", "multihash 0.19.1", "quick-protobuf", - "rand 0.8.5", + "rand", "serde", "sha2 0.10.8", "thiserror", @@ -3242,7 +3197,7 @@ dependencies = [ "log", "quick-protobuf", "quick-protobuf-codec", - "rand 0.8.5", + "rand", "serde", "sha2 0.10.8", "smallvec", @@ -3264,7 +3219,7 @@ dependencies = [ "libp2p-identity", "libp2p-swarm", "log", - "rand 0.8.5", + "rand", "smallvec", "socket2 0.5.5", "tokio", @@ -3296,7 +3251,7 @@ dependencies = [ "bytes", "curve25519-dalek", "futures", - "getrandom 0.2.15", + "getrandom", "libp2p-core", "libp2p-identity", "log", @@ -3304,7 +3259,7 @@ dependencies = [ "multihash 0.19.1", "once_cell", "quick-protobuf", - "rand 0.8.5", + "rand", "sha2 0.10.8", "snow", "static_assertions", @@ -3321,7 +3276,7 @@ dependencies = [ "futures", "log", "pin-project", - "rand 0.8.5", + "rand", "salsa20", "sha3", ] @@ -3341,7 +3296,7 @@ dependencies = [ "log", "parking_lot 0.12.1", "quinn", - "rand 0.8.5", + "rand", "ring 0.16.20", "rustls 0.23.12", "socket2 0.5.5", @@ -3351,7 +3306,7 @@ dependencies = [ [[package]] name = "libp2p-rpc-behaviour" -version = "0.9.0" +version = "0.10.0" dependencies = [ "libp2p", "log", @@ -3374,7 +3329,7 @@ dependencies = [ "log", "multistream-select", "once_cell", - "rand 0.8.5", + "rand", "smallvec", "tokio", "void", @@ -3674,6 +3629,7 @@ dependencies = [ "derive_more", "fuzzcheck", "hex", + "lazy_static", "mina-curves", "mina-hasher", "mina-poseidon", @@ -3687,6 +3643,8 @@ dependencies = [ "serde_bytes", "serde_json", "sha2 0.10.8", + "strum 0.26.2", + "strum_macros 0.26.4", "thiserror", "time", "toml", @@ -3706,7 +3664,7 @@ dependencies = [ "mina-curves", "o1-utils", "once_cell", - "rand 0.8.5", + "rand", "rayon", "serde", "serde_with 1.14.0", @@ -3726,14 +3684,14 @@ dependencies = [ "mina-curves", "mina-hasher", "o1-utils", - "rand 0.8.5", + "rand", "sha2 0.10.8", "thiserror", ] [[package]] name = "mina-transport" -version = "0.9.0" +version = "0.10.0" dependencies = [ "blake2", "hex", @@ -3744,7 +3702,7 @@ dependencies = [ [[package]] name = "mina-tree" -version = "0.9.0" +version = "0.10.0" dependencies = [ "anyhow", "ark-ec", @@ -3759,10 +3717,11 @@ dependencies = [ "crc32fast", "derive_more", "fraction", - "getrandom 0.2.15", + "getrandom", "hex", "itertools 0.10.5", "js-sys", + "juniper", "kimchi", "lazy_static", "libc", @@ -3779,7 +3738,7 @@ dependencies = [ "openmina-macros", "poly-commitment", "postcard", - "rand 0.8.5", + "rand", "rand_pcg", "rand_seeder", "rayon", @@ -3789,9 +3748,11 @@ dependencies = [ "serde_json", "serde_with 3.7.0", "sha2 0.10.8", + "strum 0.26.2", + "strum_macros 0.26.4", "thiserror", "tuple-map", - "uuid 1.5.0", + "uuid", "wasm-bindgen", "wasm-bindgen-futures", "wasm-bindgen-test", @@ -3822,7 +3783,7 @@ checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "windows-sys 0.48.0", ] @@ -4081,7 +4042,7 @@ dependencies = [ [[package]] name = "node" -version = "0.9.0" +version = "0.10.0" dependencies = [ "anyhow", "ark-ff", @@ -4174,7 +4135,7 @@ checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", - "rand 0.8.5", + "rand", "serde", ] @@ -4190,7 +4151,7 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand 0.8.5", + "rand", "smallvec", "zeroize", ] @@ -4340,8 +4301,8 @@ dependencies = [ "num-bigint", "num-integer", "num-traits", - "rand 0.8.5", - "rand_core 0.6.4", + "rand", + "rand_core", "rayon", "serde", "serde_with 1.14.0", @@ -4427,7 +4388,7 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openmina-bootstrap-sandbox" -version = "0.9.0" +version = "0.10.0" dependencies = [ "base64 0.21.7", "binprot", @@ -4442,7 +4403,7 @@ dependencies = [ "mina-transport", "mina-tree", "openmina-core", - "rand 0.8.5", + "rand", "serde", "serde_json", "structopt", @@ -4452,7 +4413,7 @@ dependencies = [ [[package]] name = "openmina-core" -version = "0.9.0" +version = "0.10.0" dependencies = [ "ark-ff", "binprot", @@ -4481,10 +4442,10 @@ dependencies = [ [[package]] name = "openmina-fuzzer" -version = "0.9.0" +version = "0.10.0" dependencies = [ "lazy_static", - "rand 0.8.5", + "rand", "rand_distr", "serde", "serde_json", @@ -4492,21 +4453,21 @@ dependencies = [ [[package]] name = "openmina-gossipsub-sandbox" -version = "0.9.0" +version = "0.10.0" dependencies = [ "bs58 0.5.0", "env_logger", "libp2p", "log", "mina-transport", - "rand 0.8.5", + "rand", "structopt", "tokio", ] [[package]] name = "openmina-macros" -version = "0.9.0" +version = "0.10.0" dependencies = [ "anyhow", "openmina-core", @@ -4519,7 +4480,7 @@ dependencies = [ [[package]] name = "openmina-node-account" -version = "0.9.0" +version = "0.10.0" dependencies = [ "anyhow", "argon2", @@ -4532,7 +4493,7 @@ dependencies = [ "mina-p2p-messages", "mina-signer", "openmina-core", - "rand 0.8.5", + "rand", "serde", "serde_json", "thiserror", @@ -4540,7 +4501,7 @@ dependencies = [ [[package]] name = "openmina-node-common" -version = "0.9.0" +version = "0.10.0" dependencies = [ "ark-ff", "gloo-timers", @@ -4552,7 +4513,7 @@ dependencies = [ "mina-tree", "node", "openmina-core", - "rand 0.8.5", + "rand", "rayon", "redux", "serde", @@ -4570,7 +4531,7 @@ dependencies = [ [[package]] name = "openmina-node-invariants" -version = "0.9.0" +version = "0.10.0" dependencies = [ "documented", "lazy_static", @@ -4584,12 +4545,12 @@ dependencies = [ [[package]] name = "openmina-node-native" -version = "0.9.0" +version = "0.10.0" dependencies = [ "anyhow", "bytes", "derive_more", - "getrandom 0.2.15", + "getrandom", "jsonpath-rust", "juniper", "juniper_warp", @@ -4601,13 +4562,15 @@ dependencies = [ "node", "openmina-core", "openmina-node-common", - "rand 0.8.5", + "rand", "rayon", "redux", "reqwest", "serde", "serde_json", "sha3", + "strum 0.26.2", + "strum_macros 0.26.4", "thiserror", "tokio", "tracing", @@ -4618,7 +4581,7 @@ dependencies = [ [[package]] name = "openmina-node-testing" -version = "0.9.0" +version = "0.10.0" dependencies = [ "anyhow", "axum", @@ -4642,7 +4605,7 @@ dependencies = [ "openmina-node-invariants", "openmina-node-native", "postcard", - "rand 0.8.5", + "rand", "rayon", "redux", "reqwest", @@ -4662,7 +4625,7 @@ dependencies = [ [[package]] name = "openmina-node-web" -version = "0.9.0" +version = "0.10.0" dependencies = [ "anyhow", "bytes", @@ -4675,7 +4638,7 @@ dependencies = [ "mina-tree", "node", "openmina-node-common", - "rand 0.8.5", + "rand", "rayon", "redux", "serde", @@ -4688,7 +4651,7 @@ dependencies = [ [[package]] name = "openmina-producer-dashboard" -version = "0.9.0" +version = "0.10.0" dependencies = [ "bincode", "clap 4.5.2", @@ -4780,7 +4743,7 @@ dependencies = [ [[package]] name = "p2p" -version = "0.9.0" +version = "0.10.0" dependencies = [ "anyhow", "binprot", @@ -4797,7 +4760,7 @@ dependencies = [ "derive_more", "ed25519-dalek", "faster-stun", - "getrandom 0.2.15", + "getrandom", "gloo-timers", "gloo-utils", "hex", @@ -4818,7 +4781,7 @@ dependencies = [ "prost", "prost-build", "quick-protobuf", - "rand 0.8.5", + "rand", "redux", "reqwest", "salsa-simple", @@ -4843,7 +4806,7 @@ dependencies = [ [[package]] name = "p2p-testing" -version = "0.9.0" +version = "0.10.0" dependencies = [ "derive_more", "futures", @@ -4855,7 +4818,7 @@ dependencies = [ "openmina-core", "p2p", "pin-project-lite", - "rand 0.8.5", + "rand", "redux", "serde_json", "thiserror", @@ -4938,7 +4901,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" dependencies = [ "base64ct", - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -5134,8 +5097,8 @@ dependencies = [ "mina-poseidon", "o1-utils", "once_cell", - "rand 0.8.5", - "rand_core 0.6.4", + "rand", + "rand_core", "rayon", "rmp-serde", "serde", @@ -5421,7 +5384,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c78e758510582acc40acb90458401172d41f1016f8c9dde89e49677afb7eec1" dependencies = [ "bytes", - "rand 0.8.5", + "rand", "ring 0.16.20", "rustc-hash", "rustls 0.21.12", @@ -5459,19 +5422,6 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", -] - [[package]] name = "rand" version = "0.8.5" @@ -5479,18 +5429,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", + "rand_chacha", + "rand_core", ] [[package]] @@ -5500,16 +5440,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", + "rand_core", ] [[package]] @@ -5518,7 +5449,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom", ] [[package]] @@ -5528,16 +5459,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" dependencies = [ "num-traits", - "rand 0.8.5", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", + "rand", ] [[package]] @@ -5546,7 +5468,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59cad018caf63deb318e5a4586d99a24424a364f40f1e5778c29aca23f4fc73e" dependencies = [ - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -5555,7 +5477,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf2890aaef0aa82719a50e808de264f9484b74b442e1a3a0e5ee38243ac40bdb" dependencies = [ - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -5637,7 +5559,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom 0.2.15", + "getrandom", "redox_syscall 0.2.16", "thiserror", ] @@ -5700,7 +5622,7 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "replay_dynamic_effects" -version = "0.9.0" +version = "0.10.0" dependencies = [ "node", "openmina-node-invariants", @@ -5790,7 +5712,7 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.15", + "getrandom", "libc", "spin 0.9.8", "untrusted 0.9.0", @@ -5832,7 +5754,7 @@ dependencies = [ "num-traits", "pkcs1", "pkcs8", - "rand_core 0.6.4", + "rand_core", "signature", "spki", "subtle", @@ -5888,7 +5810,7 @@ source = "git+https://github.com/openmina/webrtc.git?branch=openmina-v0.11.0#6f1 dependencies = [ "bytes", "portable-atomic", - "rand 0.8.5", + "rand", "serde", "thiserror", "webrtc-util", @@ -6055,12 +5977,12 @@ checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "salsa-simple" -version = "0.9.0" +version = "0.10.0" dependencies = [ "generic-array", "hex", "inout", - "rand 0.8.5", + "rand", "salsa20", "serde", "serde_json", @@ -6112,7 +6034,7 @@ name = "sdp" version = "0.6.2" source = "git+https://github.com/openmina/webrtc.git?branch=openmina-v0.11.0#6f1a6dd2dc888d4b1ad5cec61be321f12fcb44a7" dependencies = [ - "rand 0.8.5", + "rand", "substring", "thiserror", "url", @@ -6400,7 +6322,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" dependencies = [ "digest 0.10.7", - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -6457,7 +6379,7 @@ dependencies = [ [[package]] name = "snark" -version = "0.9.0" +version = "0.10.0" dependencies = [ "ark-ec", "ark-ff", @@ -6477,7 +6399,7 @@ dependencies = [ "once_cell", "openmina-core", "poly-commitment", - "rand 0.8.5", + "rand", "rayon", "redux", "serde", @@ -6497,7 +6419,7 @@ dependencies = [ "blake2", "chacha20poly1305 0.9.1", "curve25519-dalek", - "rand_core 0.6.4", + "rand_core", "ring 0.16.20", "rustc_version 0.4.0", "sha2 0.10.8", @@ -6680,7 +6602,7 @@ dependencies = [ "memchr", "once_cell", "percent-encoding", - "rand 0.8.5", + "rand", "rsa", "serde", "sha1", @@ -6719,7 +6641,7 @@ dependencies = [ "md-5", "memchr", "once_cell", - "rand 0.8.5", + "rand", "serde", "serde_json", "sha2 0.10.8", @@ -6866,7 +6788,7 @@ dependencies = [ "crc", "lazy_static", "md-5", - "rand 0.8.5", + "rand", "ring 0.17.8", "subtle", "thiserror", @@ -7325,7 +7247,7 @@ dependencies = [ "idna", "ipnet", "once_cell", - "rand 0.8.5", + "rand", "smallvec", "socket2 0.5.5", "thiserror", @@ -7347,7 +7269,7 @@ dependencies = [ "lru-cache", "once_cell", "parking_lot 0.12.1", - "rand 0.8.5", + "rand", "resolv-conf", "smallvec", "thiserror", @@ -7374,7 +7296,7 @@ dependencies = [ "http", "httparse", "log", - "rand 0.8.5", + "rand", "sha1", "thiserror", "url", @@ -7398,7 +7320,7 @@ dependencies = [ "log", "md-5", "portable-atomic", - "rand 0.8.5", + "rand", "ring 0.17.8", "stun", "thiserror", @@ -7581,19 +7503,13 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" -[[package]] -name = "uuid" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" - [[package]] name = "uuid" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc" dependencies = [ - "getrandom 0.2.15", + "getrandom", ] [[package]] @@ -7640,7 +7556,7 @@ checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" [[package]] name = "vrf" -version = "0.9.0" +version = "0.10.0" dependencies = [ "anyhow", "ark-ec", @@ -7657,7 +7573,7 @@ dependencies = [ "num", "o1-utils", "openmina-node-account", - "rand 0.8.5", + "rand", "redux", "serde", "serde_json", @@ -7720,12 +7636,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -7879,7 +7789,7 @@ dependencies = [ "lazy_static", "log", "portable-atomic", - "rand 0.8.5", + "rand", "rcgen 0.13.1", "regex", "ring 0.17.8", @@ -7941,8 +7851,8 @@ dependencies = [ "p256", "p384", "portable-atomic", - "rand 0.8.5", - "rand_core 0.6.4", + "rand", + "rand_core", "rcgen 0.13.1", "ring 0.17.8", "rustls 0.23.12", @@ -7968,7 +7878,7 @@ dependencies = [ "crc", "log", "portable-atomic", - "rand 0.8.5", + "rand", "serde", "serde_json", "stun", @@ -7976,7 +7886,7 @@ dependencies = [ "tokio", "turn", "url", - "uuid 1.5.0", + "uuid", "waitgroup", "webrtc-mdns", "webrtc-util", @@ -8001,7 +7911,7 @@ source = "git+https://github.com/openmina/webrtc.git?branch=openmina-v0.11.0#6f1 dependencies = [ "byteorder", "bytes", - "rand 0.8.5", + "rand", "rtp", "thiserror", ] @@ -8017,7 +7927,7 @@ dependencies = [ "crc", "log", "portable-atomic", - "rand 0.8.5", + "rand", "thiserror", "tokio", "webrtc-util", @@ -8059,7 +7969,7 @@ dependencies = [ "log", "nix 0.26.4", "portable-atomic", - "rand 0.8.5", + "rand", "thiserror", "tokio", "winapi", @@ -8355,7 +8265,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb66477291e7e8d2b0ff1bcb900bf29489a9692816d79874bea351e7a8b6de96" dependencies = [ "curve25519-dalek", - "rand_core 0.6.4", + "rand_core", "serde", "zeroize", ] @@ -8421,7 +8331,7 @@ dependencies = [ "nohash-hasher", "parking_lot 0.12.1", "pin-project", - "rand 0.8.5", + "rand", "static_assertions", ] diff --git a/Cargo.toml b/Cargo.toml index 109af34b2a..610314fb5a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,6 +53,8 @@ serde_json = "1.0.107" serde_with = { version = "3.7.0", features = ["hex"] } linkme = "0.3.22" static_assertions = "1.1.0" +juniper = { version = "0.16" } + [profile.fuzz] inherits = "release" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index a9a57b1c8e..9a425f3de5 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cli" -version = "0.9.0" +version = "0.10.0" edition = "2021" license = "Apache-2.0" diff --git a/cli/replay_dynamic_effects/Cargo.toml b/cli/replay_dynamic_effects/Cargo.toml index 5e39c98387..973f78644d 100644 --- a/cli/replay_dynamic_effects/Cargo.toml +++ b/cli/replay_dynamic_effects/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "replay_dynamic_effects" -version = "0.9.0" +version = "0.10.0" edition = "2021" license = "Apache-2.0" diff --git a/core/Cargo.toml b/core/Cargo.toml index d8e0162164..550e1551e6 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openmina-core" -version = "0.9.0" +version = "0.10.0" edition = "2021" license = "Apache-2.0" diff --git a/core/src/consensus.rs b/core/src/consensus.rs index a2041ea110..5429dbf07d 100644 --- a/core/src/consensus.rs +++ b/core/src/consensus.rs @@ -3,6 +3,7 @@ use mina_p2p_messages::v2::{ ConsensusProofOfStakeDataConsensusStateValueStableV2 as MinaConsensusState, StateHash, }; use serde::{Deserialize, Serialize}; +use time::{macros::format_description, OffsetDateTime}; use crate::constants::constraint_constants; pub use crate::constants::{ @@ -301,6 +302,13 @@ impl ConsensusConstants { constants.assert_invariants(); constants } + + pub fn human_readable_genesis_timestamp(&self) -> Result { + let format = format_description!("[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond digits:6][offset_hour sign:mandatory]:[offset_minute]"); + OffsetDateTime::from_unix_timestamp((self.genesis_state_timestamp.as_u64() / 1000) as i64) + .map_err(|e| e.to_string()) + .and_then(|dt| dt.format(&format).map_err(|e| e.to_string())) + } } #[cfg(test)] diff --git a/core/src/dummy/mod.rs b/core/src/dummy/mod.rs index 5830d60bdb..4bbe705f0a 100644 --- a/core/src/dummy/mod.rs +++ b/core/src/dummy/mod.rs @@ -1,8 +1,8 @@ use std::sync::Arc; -use binprot::BinProtRead; use mina_p2p_messages::v2::{MinaBaseProofStableV2, TransactionSnarkProofStableV2}; +// NOTE: moved to mina_p2p_messages crate /// Value of `Proof.transaction_dummy` when we run `dune runtest src/lib/staged_ledger -f` /// The file was generated this way: /// @@ -19,28 +19,10 @@ use mina_p2p_messages::v2::{MinaBaseProofStableV2, TransactionSnarkProofStableV2 /// Core.Printf.eprintf !"dummy proof= %{sexp: Proof.t}\n%!" dummy; /// Core.Printf.eprintf !"dummy proof= %s\n%!" s; pub fn dummy_transaction_proof() -> Arc { - lazy_static::lazy_static! { - static ref DUMMY_PROOF: Arc = { - let bytes = include_bytes!("dummy_transaction_proof.bin"); - TransactionSnarkProofStableV2::binprot_read(&mut bytes.as_slice()) - .unwrap() - .into() - }; - } - - DUMMY_PROOF.clone() + mina_p2p_messages::v2::dummy_transaction_proof() } /// Value of `Proof.blockchain_dummy` pub fn dummy_blockchain_proof() -> Arc { - lazy_static::lazy_static! { - static ref DUMMY_PROOF: Arc = { - let bytes = include_bytes!("dummy_blockchain_proof.bin"); - MinaBaseProofStableV2::binprot_read(&mut bytes.as_slice()) - .unwrap() - .into() - }; - } - - DUMMY_PROOF.clone() + mina_p2p_messages::v2::dummy_blockchain_proof() } diff --git a/core/src/log.rs b/core/src/log.rs index c80085056c..b1883e5f06 100644 --- a/core/src/log.rs +++ b/core/src/log.rs @@ -78,12 +78,20 @@ pub const ACTION_TRACE_TARGET: &str = "openmina_core::log::action"; #[macro_export] macro_rules! action_event { ($level:expr, $context:expr, $($tts:tt)*) => { - $crate::log::inner::event!(target: { $crate::log::ACTION_TRACE_TARGET }, $level, time = $context.time(), node_id = $context.node_id(), $($tts)*) + if $context.log_node_id() { + $crate::log::inner::event!(target: { $crate::log::ACTION_TRACE_TARGET }, $level, time = $context.time(), node_id = $context.node_id(), $($tts)*) + } else { + $crate::log::inner::event!(target: { $crate::log::ACTION_TRACE_TARGET }, $level, time = $context.time(), $($tts)*) + } }; ($level:expr, $context:expr) => { - $crate::log::inner::event!(target: { $crate::log::ACTION_TRACE_TARGET }, $level, time = $context.time(), node_id = $context.node_id()) + if $context.log_node_id() { + $crate::log::inner::event!(target: { $crate::log::ACTION_TRACE_TARGET }, $level, time = $context.time(), node_id = $context.node_id()) + } else { + $crate::log::inner::event!(target: { $crate::log::ACTION_TRACE_TARGET }, $level, time = $context.time()) + } }; - } +} #[macro_export] macro_rules! action_error { @@ -139,6 +147,7 @@ pub trait EventContext { fn timestamp(&self) -> redux::Timestamp; fn time(&self) -> &'_ dyn Value; fn node_id(&self) -> &'_ dyn Value; + fn log_node_id(&self) -> bool; } pub trait ActionEvent { diff --git a/docker-compose.local.producers.yml b/docker-compose.local.producers.yml index 08e7cc08ad..40b46eca97 100644 --- a/docker-compose.local.producers.yml +++ b/docker-compose.local.producers.yml @@ -1,7 +1,7 @@ services: local-producer-cluster: container_name: local-producer-cluster - image: openmina/openmina:0.9.0 + image: openmina/openmina:0.10.0 environment: - RUST_BACKTRACE=1 entrypoint: ["openmina-node-testing", "scenarios-generate", "--name", "simulation-small-forever-real-time"] @@ -12,7 +12,7 @@ services: frontend: container_name: frontend - image: openmina/frontend:0.9.0 + image: openmina/frontend:0.10.0 environment: OPENMINA_FRONTEND_ENVIRONMENT: block_producers ports: diff --git a/frontend/.gitignore b/frontend/.gitignore index a38ab81b20..e10321af5a 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -40,3 +40,7 @@ testem.log # System files .DS_Store Thumbs.db + +# Open Mina +/src/assets/webnode/pkg +/src/assets/webnode/circuit-blobs diff --git a/frontend/README.md b/frontend/README.md index 70f0a9ac5a..ded497ce4c 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -7,12 +7,14 @@ This is a simple Angular application that will help you to see the behaviour of ### 1. Node.js v20.11.1 #### MacOS + ```bash /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" brew install node@20.11.1 ``` #### Linux + ```bash curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash source ~/.bashrc @@ -20,20 +22,25 @@ nvm install 20.11.1 ``` #### Windows + Download [Node.js v20.11.1](https://nodejs.org/) from the official website, open the installer and follow the prompts to complete the installation. ### 2. Angular CLI v16.2.0 + ```bash npm install -g @angular/cli@16.2.0 ``` ### 3. Installation + Open a terminal and navigate to this project's root directory ```bash cd PROJECT_LOCATION/openmina/frontend ``` + Install the dependencies + ```bash npm install ``` @@ -43,3 +50,24 @@ npm install ```bash npm start ``` + +# Using O1JS wrapper + +as of now, o1js is not prepared to work with Angular, therefore we need to use the wrapper that is provided in the `src/assets/o1js` folder. This wrapper is a simple javascript webpack based application that will allow us to use the o1js library in our Angular application. + +How to use it: + +1. Open a terminal and navigate to the `src/assets/o1js` folder +2. Install the dependencies + +```bash +npm install +``` + +3. Build the wrapper + +```bash +npm run build-o1jswrapper +``` + +4. That's it. Now you can use your code from o1js-wrapper inside the Angular application by using `BenchmarksWalletsZkService => o1jsInterface` diff --git a/frontend/angular.json b/frontend/angular.json index 92c363c98c..ca9c830cd4 100644 --- a/frontend/angular.json +++ b/frontend/angular.json @@ -112,15 +112,6 @@ } ], "outputHashing": "all" - }, - "staging": { - "fileReplacements": [ - { - "replace": "src/environments/environment.ts", - "with": "src/environments/environment.staging.ts" - } - ], - "outputHashing": "all" } }, "defaultConfiguration": "production" diff --git a/frontend/package-lock.json b/frontend/package-lock.json index e89e5f25c7..c943e4f6a1 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -32,7 +32,6 @@ "mathjs": "^12.3.0", "mina-signer": "^3.0.7", "ngx-json-viewer": "^3.2.1", - "o1js": "^1.8.0", "rxjs": "~7.8.0", "tslib": "^2.3.0", "zone.js": "~0.13.0" @@ -5539,6 +5538,7 @@ }, "node_modules/cachedir": { "version": "2.4.0", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -7258,6 +7258,7 @@ }, "node_modules/encoding": { "version": "0.1.13", + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -7266,6 +7267,7 @@ }, "node_modules/encoding/node_modules/iconv-lite": { "version": "0.6.3", + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -9142,15 +9144,6 @@ "node": ">=0.10.0" } }, - "node_modules/isomorphic-fetch": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz", - "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==", - "dependencies": { - "node-fetch": "^2.6.1", - "whatwg-fetch": "^3.4.1" - } - }, "node_modules/isstream": { "version": "0.1.2", "dev": true, @@ -10771,44 +10764,6 @@ "license": "MIT", "optional": true }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-fetch/node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "node_modules/node-fetch/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/node-fetch/node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "node_modules/node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", @@ -11121,25 +11076,6 @@ "dev": true, "license": "MIT" }, - "node_modules/o1js": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/o1js/-/o1js-1.8.0.tgz", - "integrity": "sha512-mN0aM4HW3kyl/Gx0irqKQSQ2JftbmsK2t5nSZpTuNgTOVl0wQ6KZumXXps6E5hGkCjRfk+FjlL7CBsmqKqzYzg==", - "dependencies": { - "blakejs": "1.2.1", - "cachedir": "^2.4.0", - "isomorphic-fetch": "^3.0.0", - "js-sha256": "^0.9.0", - "reflect-metadata": "^0.1.13", - "tslib": "^2.3.0" - }, - "bin": { - "snarky-run": "src/build/run.js" - }, - "engines": { - "node": ">=18.14.0" - } - }, "node_modules/object-assign": { "version": "4.1.1", "dev": true, @@ -12140,6 +12076,7 @@ }, "node_modules/reflect-metadata": { "version": "0.1.13", + "dev": true, "license": "Apache-2.0" }, "node_modules/regenerate": { @@ -14600,11 +14537,6 @@ "iconv-lite": "0.4.24" } }, - "node_modules/whatwg-fetch": { - "version": "3.6.20", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", - "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==" - }, "node_modules/whatwg-mimetype": { "version": "2.3.0", "dev": true, diff --git a/frontend/package.json b/frontend/package.json index 5224d85e06..1439464d75 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,8 +10,7 @@ "watch": "ng build --watch --configuration development", "tests": "npx cypress open --config baseUrl=http://localhost:4200", "tests:headless": "npx cypress run --headless --config baseUrl=http://localhost:4200", - "docker": "npm run build:prod && docker buildx build --platform linux/amd64 -t openmina/frontend:latest . && docker push openmina/frontend:latest", - "replace-assertion": "node replace-assertion.js" + "docker": "npm run build:prod && docker buildx build --platform linux/amd64 -t openmina/frontend:latest . && docker push openmina/frontend:latest" }, "private": true, "dependencies": { @@ -39,7 +38,6 @@ "mathjs": "^12.3.0", "mina-signer": "^3.0.7", "ngx-json-viewer": "^3.2.1", - "o1js": "^1.8.0", "rxjs": "~7.8.0", "tslib": "^2.3.0", "zone.js": "~0.13.0" diff --git a/frontend/src/app/app.component.ts b/frontend/src/app/app.component.ts index 8ae7e251a8..ccf2f503e9 100644 --- a/frontend/src/app/app.component.ts +++ b/frontend/src/app/app.component.ts @@ -8,26 +8,6 @@ import { AppSelectors } from '@app/app.state'; import { AppActions } from '@app/app.actions'; import { Observable, timer } from 'rxjs'; import { CONFIG } from '@shared/constants/config'; -// import { AccountUpdate, declareMethods, Field, method, Mina, PrivateKey, SmartContract, State, state } from 'o1js'; -// -// export class Square extends SmartContract { -// @state(Field) num = State(); -// -// override init() { -// super.init(); -// this.num.set(Field(3)); -// } -// -// // @method -// async update(square: Field) { -// const currentState = this.num.get(); -// this.num.requireEquals(currentState); -// square.assertEquals(currentState.mul(currentState)); -// this.num.set(square); -// } -// } - -declare const $: any; @Component({ selector: 'app-root', @@ -38,7 +18,7 @@ declare const $: any; }) export class AppComponent extends ManualDetection implements OnInit { - menu$: Observable = this.store.select(AppSelectors.menu); + protected readonly menu$: Observable = this.store.select(AppSelectors.menu); subMenusLength: number = 0; hideToolbar: boolean = CONFIG.hideToolbar; @@ -51,108 +31,13 @@ export class AppComponent extends ManualDetection implements OnInit { } } - async ngOnInit() { + ngOnInit(): void { if (!this.hideToolbar && !CONFIG.hideNodeStats) { this.scheduleNodeUpdates(); } this.listenToWindowResizing(); - // console.log('Start'); - // // this.startZK(); - // console.log('Finish!'); - // try { - // await this.loadScript('assets/o1js/main.js'); - // // Now the script is loaded, and you can access the exported variable - // if (typeof (window as any).$ !== 'undefined') { - // const $ = (window as any).$; - // console.log('Script loaded:', $); - // // Use $ here - // $.default.gql4(); - // } else { - // console.error('$ is not defined after loading the script'); - // } - // } catch (error) { - // console.error('Error loading script:', error); - // } - } - - loadScript(scriptUrl: string): Promise { - return new Promise((resolve, reject) => { - const script = document.createElement('script'); - script.src = scriptUrl; - script.onload = () => resolve(); - script.onerror = (error) => reject(error); - document.body.appendChild(script); - }); } -// async startZK() { -// //@ts-ignore -// declareMethods(Square, { update: [Field] }); -// -// const useProof = false; -// -// const Local = await Mina.LocalBlockchain({ proofsEnabled: useProof }); -// Mina.setActiveInstance(Local); -// -// const deployerAccount = Local.testAccounts[0]; -// const deployerKey = deployerAccount.key; -// const senderAccount = Local.testAccounts[1]; -// const senderKey = senderAccount.key; -// // ---------------------------------------------------- -// -// // Create a public/private key pair. The public key is your address and where you deploy the zkApp to -// const zkAppPrivateKey = PrivateKey.random(); -// const zkAppAddress = zkAppPrivateKey.toPublicKey(); -// -// // create an instance of Square - and deploy it to zkAppAddress -// const zkAppInstance = new Square(zkAppAddress); -// const deployTxn = await Mina.transaction(deployerAccount, async () => { -// AccountUpdate.fundNewAccount(deployerAccount); -// await zkAppInstance.deploy(); -// }); -// await deployTxn.sign([deployerKey, zkAppPrivateKey]).send(); -// -// // get the initial state of Square after deployment -// const num0 = zkAppInstance.num.get(); -// console.log('state after init:', num0.toString()); -// -// // ---------------------------------------------------- -// -// const txn1 = await Mina.transaction(senderAccount, async () => { -// await zkAppInstance.update(Field(9)); -// }); -// await txn1.prove(); -// await txn1.sign([senderKey]).send(); -// -// const num1 = zkAppInstance.num.get(); -// console.log('state after txn1:', num1.toString()); -// -// // ---------------------------------------------------- -// -// try { -// const txn2 = await Mina.transaction(senderAccount, async () => { -// await zkAppInstance.update(Field(75)); -// }); -// await txn2.prove(); -// await txn2.sign([senderKey]).send(); -// } catch (error: any) { -// console.log(error.message); -// } -// const num2 = zkAppInstance.num.get(); -// console.log('state after txn2:', num2.toString()); -// -// // ---------------------------------------------------- -// -// const txn3 = await Mina.transaction(senderAccount, async () => { -// await zkAppInstance.update(Field(81)); -// }); -// await txn3.prove(); -// await txn3.sign([senderKey]).send(); -// -// const num3 = zkAppInstance.num.get(); -// console.log('state after txn3:', num3.toString()); -// } - private scheduleNodeUpdates(): void { timer(1000, 5000).subscribe(() => this.store.dispatch(AppActions.getNodeDetails())); } diff --git a/frontend/src/app/app.effects.ts b/frontend/src/app/app.effects.ts index 31c3c99799..322ccbd751 100644 --- a/frontend/src/app/app.effects.ts +++ b/frontend/src/app/app.effects.ts @@ -2,7 +2,7 @@ import { Injectable } from '@angular/core'; import { MinaState, selectMinaState } from '@app/app.setup'; import { Actions, createEffect, ofType } from '@ngrx/effects'; import { Store } from '@ngrx/store'; -import { createNonDispatchableEffect, Effect, removeParamsFromURL } from '@openmina/shared'; +import { createNonDispatchableEffect, Effect, NonDispatchableEffect, removeParamsFromURL } from '@openmina/shared'; import { filter, from, map, switchMap, tap } from 'rxjs'; import { AppActions } from '@app/app.actions'; import { Router } from '@angular/router'; @@ -25,6 +25,7 @@ export class AppEffects extends BaseEffect { readonly initEffects$: Effect; readonly init$: Effect; + readonly initSuccess$: NonDispatchableEffect; readonly onNodeChange$: Effect; readonly getNodeDetails$: Effect; @@ -53,6 +54,19 @@ export class AppEffects extends BaseEffect { map((payload: { activeNode: MinaNode, nodes: MinaNode[] }) => AppActions.initSuccess(payload)), )); + this.initSuccess$ = createNonDispatchableEffect(() => this.actions$.pipe( + ofType(AppActions.initSuccess), + this.latestActionState(), + switchMap(({ state }) => { + if (state.app.activeNode.isWebNode) { + return this.webNodeService.loadWasm$().pipe( + switchMap(() => this.webNodeService.startWasm$()), + ); + } + return from([]); + }), + )); + this.onNodeChange$ = createNonDispatchableEffect(() => this.actions$.pipe( ofType(AppActions.changeActiveNode), this.latestActionState(), diff --git a/frontend/src/app/app.routing.ts b/frontend/src/app/app.routing.ts index aa4c02e7da..7918f7fd26 100644 --- a/frontend/src/app/app.routing.ts +++ b/frontend/src/app/app.routing.ts @@ -68,11 +68,6 @@ const routes: Routes = [ loadChildren: () => import('./features/benchmarks/benchmarks.module').then(m => m.BenchmarksModule), title: BENCHMARKS_TITLE, }, - { - path: 'zk', - loadChildren: () => import('./features/zk/zk.module').then(m => m.ZkModule), - title: BENCHMARKS_TITLE, - }, { path: '**', redirectTo: getFirstFeature(), diff --git a/frontend/src/app/app.service.ts b/frontend/src/app/app.service.ts index 94d6135d44..700a0a3f69 100644 --- a/frontend/src/app/app.service.ts +++ b/frontend/src/app/app.service.ts @@ -32,7 +32,7 @@ export class AppService { .pipe( map((data: NodeDetailsResponse) => ({ status: this.getStatus(data), - blockHeight: data.transition_frontier.best_tip.height, + blockHeight: data.transition_frontier.best_tip?.height, blockTime: data.transition_frontier.sync.time, peers: data.peers.filter(p => p.connection_status === 'Connected').length, download: 0, diff --git a/frontend/src/app/core/services/web-node.service.ts b/frontend/src/app/core/services/web-node.service.ts index db550faf6d..e595e5d00a 100644 --- a/frontend/src/app/core/services/web-node.service.ts +++ b/frontend/src/app/core/services/web-node.service.ts @@ -2,6 +2,7 @@ import { Injectable } from '@angular/core'; import { BehaviorSubject, filter, from, fromEvent, map, Observable, of, switchMap, tap } from 'rxjs'; import base from 'base-x'; import { any, log } from '@openmina/shared'; +import { CONFIG } from '@shared/constants/config'; @Injectable({ providedIn: 'root', @@ -21,8 +22,6 @@ export class WebNodeService { } loadWasm$(): Observable { - console.log('loading WASM'); - console.log((window as any).webnode); if ((window as any).webnode) { return of(void 0); } @@ -30,19 +29,17 @@ export class WebNodeService { } startWasm$(): Observable { - console.log('starting WASM'); return of((window as any).webnode) .pipe( switchMap((wasm: any) => from(wasm.default('assets/webnode/pkg/openmina_node_web_bg.wasm')).pipe(map(() => wasm))), switchMap((wasm) => { console.log(wasm); - return from(wasm.run()); + return from(wasm.run(CONFIG.webNodeKey)); }), tap((jsHandle: any) => { this.backend = jsHandle; - console.log('----------------JS HANDLE----------------'); + console.log('----------------WEBNODE----------------'); console.log(jsHandle); - console.log('----------------JS HANDLE----------------'); this.backendSubject$.next(jsHandle); }), switchMap(() => this.backendSubject$.asObservable()), diff --git a/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets-toolbar/benchmarks-wallets-toolbar.component.html b/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets-toolbar/benchmarks-wallets-toolbar.component.html index 6d3f1234c3..099ebdc2ba 100644 --- a/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets-toolbar/benchmarks-wallets-toolbar.component.html +++ b/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets-toolbar/benchmarks-wallets-toolbar.component.html @@ -3,7 +3,7 @@
diff --git a/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets-zk.service.ts b/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets-zk.service.ts index fa8f45afdf..5bcbf1dc98 100644 --- a/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets-zk.service.ts +++ b/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets-zk.service.ts @@ -1,18 +1,21 @@ -import { Injectable } from '@angular/core'; -import { BehaviorSubject, filter, map, Observable, switchMap } from 'rxjs'; +import { inject, Injectable } from '@angular/core'; +import { BehaviorSubject, catchError, filter, map, Observable, of, switchMap } from 'rxjs'; import { BenchmarksZkapp } from '@shared/types/benchmarks/transactions/benchmarks-zkapp.type'; import { fromPromise } from 'rxjs/internal/observable/innerFrom'; import { CONFIG } from '@shared/constants/config'; import { any } from '@openmina/shared'; +import { DOCUMENT } from '@angular/common'; @Injectable() export class BenchmarksWalletsZkService { private readonly updates = new BehaviorSubject<{ step: string, duration: number }>(null); private readonly o1jsInterface: BehaviorSubject = new BehaviorSubject(null); + private readonly document: Document = inject(DOCUMENT); readonly updates$ = this.updates.asObservable(); + loadO1js(): void { this.loadScript(); } @@ -24,16 +27,29 @@ export class BenchmarksWalletsZkService { return this.o1jsInterface.pipe( filter(Boolean), switchMap((o1js: any) => { - return fromPromise(o1js.sendZkApp(CONFIG.globalConfig?.graphQL, zkApps[0], this.updates)); + const executeSequentially = async (): Promise => { + const results: any[] = []; + for (const zkApp of zkApps) { + const response = await o1js.updateZkApp(CONFIG.globalConfig?.graphQL, zkApp, this.updates); + results.push(response); + } + return results; + }; + + return fromPromise(executeSequentially()); }), - map((response: any) => { - if (response.errors[0]) { - let error = new Error(response.errors[0]); - error.name = response.status; + map((responses: any[]) => { + const errors = responses.filter(response => response.errors && response.errors[0]); + if (errors.length > 0) { + let error = new Error(errors[0].errors[0]); + error.name = errors[0].status; return { error, zkApps }; } return { zkApps }; }), + catchError((error: Error) => { + return of({ error, zkApps }); + }), ); } @@ -41,11 +57,11 @@ export class BenchmarksWalletsZkService { if (any(window).o1jsWrapper) { return; } - const script = document.createElement('script'); - script.src = 'assets/o1js/o1jsWrapper.js'; + const script = this.document.createElement('script'); + script.src = 'assets/o1js/dist/o1js-wrapper.js'; script.onload = () => { this.o1jsInterface.next(any(window).o1jsWrapper.default); }; - document.body.appendChild(script); + this.document.body.appendChild(script); } } diff --git a/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets-zkapp-toolbar/benchmarks-wallets-zkapp-toolbar.component.html b/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets-zkapp-toolbar/benchmarks-wallets-zkapp-toolbar.component.html index 435bad5e90..2abbc809a2 100644 --- a/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets-zkapp-toolbar/benchmarks-wallets-zkapp-toolbar.component.html +++ b/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets-zkapp-toolbar/benchmarks-wallets-zkapp-toolbar.component.html @@ -3,7 +3,7 @@
@@ -40,9 +40,12 @@ arrow_drop_down
- - - +
+ + {{ updates.step }} {{ updates.duration }}s + +
diff --git a/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets.reducer.ts b/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets.reducer.ts index dbf0e0c6e4..326dba5040 100644 --- a/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets.reducer.ts +++ b/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets.reducer.ts @@ -306,7 +306,7 @@ export function reducer(state: BenchmarksWalletsState = initialState, action: Be fee: state.sendingFeeZkapps, nonce, memo, - accountUpdates: 8, + accountUpdates: 2, }; }); } else { @@ -322,7 +322,7 @@ export function reducer(state: BenchmarksWalletsState = initialState, action: Be fee: state.sendingFeeZkapps, nonce: nonce.toString(), memo, - accountUpdates: 8, + accountUpdates: 2, }; nonce++; diff --git a/frontend/src/app/features/dashboard/dashboard-errors/dashboard-errors.component.html b/frontend/src/app/features/dashboard/dashboard-errors/dashboard-errors.component.html deleted file mode 100644 index 86db8302e7..0000000000 --- a/frontend/src/app/features/dashboard/dashboard-errors/dashboard-errors.component.html +++ /dev/null @@ -1,19 +0,0 @@ -
-
-
{{ resyncs.length }} Failed attempts
- unfold_{{ open ? 'less' : 'more' }} -
-
-
-
-
{{ item.kind }}
-
{{ item.description }}
-
-
{{ item.timeAgo }}
-
-
-
diff --git a/frontend/src/app/features/dashboard/dashboard-errors/dashboard-errors.component.scss b/frontend/src/app/features/dashboard/dashboard-errors/dashboard-errors.component.scss deleted file mode 100644 index 44d397578c..0000000000 --- a/frontend/src/app/features/dashboard/dashboard-errors/dashboard-errors.component.scss +++ /dev/null @@ -1,26 +0,0 @@ -@import 'openmina'; - -::ng-deep body.light mina-dashboard-errors .acc-header { - border: 1px solid transparent; - - &:hover { - border: 1px solid $base-divider; - } -} - -.errors-list { - transition: 0.2s ease-in-out; - - &:not(.open) { - max-height: 0 !important; - } - - &.open { - max-height: 110px; - } - - .resync { - height: 28px; - line-height: 28px; - } -} diff --git a/frontend/src/app/features/dashboard/dashboard-errors/dashboard-errors.component.ts b/frontend/src/app/features/dashboard/dashboard-errors/dashboard-errors.component.ts deleted file mode 100644 index 2f92a5361d..0000000000 --- a/frontend/src/app/features/dashboard/dashboard-errors/dashboard-errors.component.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; -import { StoreDispatcher } from '@shared/base-classes/store-dispatcher.class'; -import { selectDashboardNodes } from '@dashboard/dashboard.state'; -import { NodesOverviewNode } from '@shared/types/nodes/dashboard/nodes-overview-node.type'; -import { ONE_MILLION } from '@openmina/shared'; -import { filter } from 'rxjs'; -import { - NodesOverviewResync, - NodesOverviewResyncKindType, - NodesOverviewResyncUI, -} from '@shared/types/nodes/dashboard/nodes-overview-resync.type'; - -const descriptionMap = { - [NodesOverviewResyncKindType.RootLedgerChange]: 'Root snarked ledger needs to be re-synced.', - [NodesOverviewResyncKindType.FetchStagedLedgerError]: 'Root staging ledger needs to be re-synced.', - [NodesOverviewResyncKindType.EpochChange]: 'Next epoch ledger needs to be re-synced.', - [NodesOverviewResyncKindType.BestChainChange]: 'Staking epoch ledger needs to be re-synced.', -}; - -@Component({ - selector: 'mina-dashboard-errors', - templateUrl: './dashboard-errors.component.html', - styleUrls: ['./dashboard-errors.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class DashboardErrorsComponent extends StoreDispatcher implements OnInit { - - resyncs: NodesOverviewResyncUI[] = []; - open: boolean; - readonly trackResyncs = (_: number, resync: NodesOverviewResyncUI) => resync.kind + resync.timeAgo; - - ngOnInit(): void { - this.listenToNodesChanges(); - } - - private listenToNodesChanges(): void { - this.select(selectDashboardNodes, (nodes: NodesOverviewNode[]) => { - if (this.resyncs.length === 0 && nodes[0].resyncs.length > 0) { - this.open = true; - } - this.mapResyncs(nodes[0].resyncs); - this.detect(); - }, filter(n => n.length > 0)); - } - - private mapResyncs(resyncs: NodesOverviewResync[]): void { - this.resyncs = resyncs.slice().reverse().map(resync => ({ - ...resync, - description: resync.description ?? descriptionMap[resync.kind], - timeAgo: this.calculateProgressTime(resync.time), - } as NodesOverviewResyncUI)); - } - - private calculateProgressTime(timestamp: number): string { - timestamp = Math.ceil(timestamp / ONE_MILLION); - const millisecondsAgo = Date.now() - timestamp; - const minutesAgo = Math.floor(millisecondsAgo / 1000 / 60); - const hoursAgo = Math.floor(minutesAgo / 60); - const daysAgo = Math.floor(hoursAgo / 24); - - if (daysAgo > 0) { - return `${daysAgo}d ago`; - } else if (hoursAgo > 0) { - return `${hoursAgo}h ago`; - } else if (minutesAgo > 0) { - return `${minutesAgo}m ago`; - } else { - return `<1m ago`; - } - } -} diff --git a/frontend/src/app/features/dashboard/dashboard-transition-frontier/dashboard-transition-frontier.component.html b/frontend/src/app/features/dashboard/dashboard-transition-frontier/dashboard-transition-frontier.component.html index e08c9074ad..549dcca28f 100644 --- a/frontend/src/app/features/dashboard/dashboard-transition-frontier/dashboard-transition-frontier.component.html +++ b/frontend/src/app/features/dashboard/dashboard-transition-frontier/dashboard-transition-frontier.component.html @@ -3,7 +3,6 @@ Transition frontier -
diff --git a/frontend/src/app/features/dashboard/dashboard-transition-frontier/dashboard-transition-frontier.component.scss b/frontend/src/app/features/dashboard/dashboard-transition-frontier/dashboard-transition-frontier.component.scss index 07948d87f5..17d80cb52d 100644 --- a/frontend/src/app/features/dashboard/dashboard-transition-frontier/dashboard-transition-frontier.component.scss +++ b/frontend/src/app/features/dashboard/dashboard-transition-frontier/dashboard-transition-frontier.component.scss @@ -1,11 +1,5 @@ @import 'openmina'; -mina-dashboard-errors { - display: block; - width: 100%; - max-width: calc(410px + 640px + 10px); -} - .tracing-container { gap: 8px; diff --git a/frontend/src/app/features/dashboard/dashboard.effects.ts b/frontend/src/app/features/dashboard/dashboard.effects.ts index 193f982722..adc3a62f6d 100644 --- a/frontend/src/app/features/dashboard/dashboard.effects.ts +++ b/frontend/src/app/features/dashboard/dashboard.effects.ts @@ -60,15 +60,7 @@ export class DashboardEffects extends MinaRustBaseEffect { name: state.app.activeNode.name, }), this.dashboardService.getRpcCalls(), - ]).pipe( - // tap((r) => { - // console.log('RESPONSE FROM COMBINATION', r); - // }), - // catchError((err) => { - // console.log('ERROR FROM COMBINATION', err); - // return EMPTY; - // }), - ), + ]), ), map((payload: [DashboardPeer[], NodesOverviewNode[], DashboardRpcStats]) => ({ type: DASHBOARD_GET_DATA_SUCCESS, payload: { peers: payload[0], ledger: payload[1], rpcStats: payload[2] }, diff --git a/frontend/src/app/features/dashboard/dashboard.module.ts b/frontend/src/app/features/dashboard/dashboard.module.ts index da29017fa0..4eaa8de27d 100644 --- a/frontend/src/app/features/dashboard/dashboard.module.ts +++ b/frontend/src/app/features/dashboard/dashboard.module.ts @@ -18,7 +18,6 @@ import { DashboardTransitionFrontierComponent, } from './dashboard-transition-frontier/dashboard-transition-frontier.component'; import { DashboardBlocksSyncComponent } from './dashboard-blocks-sync/dashboard-blocks-sync.component'; -import { DashboardErrorsComponent } from './dashboard-errors/dashboard-errors.component'; import { DashboardPeersMinimalTableComponent, } from './dashboard-peers-minimal-table/dashboard-peers-minimal-table.component'; @@ -36,7 +35,6 @@ import { DashboardLedgerComponent, DashboardTransitionFrontierComponent, DashboardBlocksSyncComponent, - DashboardErrorsComponent, DashboardPeersMinimalTableComponent, ], imports: [ diff --git a/frontend/src/app/features/dashboard/dashboard.service.ts b/frontend/src/app/features/dashboard/dashboard.service.ts index 3f75b7356f..889502a595 100644 --- a/frontend/src/app/features/dashboard/dashboard.service.ts +++ b/frontend/src/app/features/dashboard/dashboard.service.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core'; -import { catchError, map, Observable } from 'rxjs'; +import { catchError, map, Observable, tap } from 'rxjs'; import { DashboardPeer, DashboardPeerStatus } from '@shared/types/dashboard/dashboard.peer'; import { RustService } from '@core/services/rust.service'; import { ONE_MILLION, toReadableDate } from '@openmina/shared'; @@ -30,11 +30,6 @@ export class DashboardService { requests: 0, } as DashboardPeer)), ), - // tap((peers: any) => { - // console.log('----------------PEERS----------------'); - // console.log(peers); - // console.log('----------------PEERS----------------'); - // }), ); } @@ -48,22 +43,12 @@ export class DashboardService { name, url, })), - // tap((peers: any) => { - // console.log('----------------SYNC----------------'); - // console.log(peers); - // console.log('----------------SYNC----------------'); - // }), ); } getRpcCalls(): Observable { return this.rust.get('/state/message-progress').pipe( map((response: MessageProgressResponse) => this.mapMessageProgressResponse(response)), - // tap((peers: any) => { - // console.log('----------------MESSAGES----------------'); - // console.log(peers); - // console.log('----------------MESSAGES----------------'); - // }), ); } diff --git a/frontend/src/app/features/nodes/overview/nodes-overview.service.ts b/frontend/src/app/features/nodes/overview/nodes-overview.service.ts index e210b46126..7a15f2e2c8 100644 --- a/frontend/src/app/features/nodes/overview/nodes-overview.service.ts +++ b/frontend/src/app/features/nodes/overview/nodes-overview.service.ts @@ -12,7 +12,6 @@ import { NodesOverviewLedgerEpochStep, NodesOverviewLedgerStepState, } from '@shared/types/nodes/dashboard/nodes-overview-ledger.type'; -import { NodesOverviewResync } from '@shared/types/nodes/dashboard/nodes-overview-resync.type'; import { NodeDetailsResponse } from '@app/app.service'; @Injectable({ @@ -50,7 +49,6 @@ export class NodesOverviewService { fetchedBlocks: 0, fetchingBlocks: 0, ledgers: this.getLedgers({}), - resyncs: [], blocks: [], }]); } @@ -96,7 +94,6 @@ export class NodesOverviewService { fetchedBlocks: node.blocks.filter((block: any) => block.status === NodesOverviewNodeBlockStatus.FETCHED).length, fetchingBlocks: node.blocks.filter((block: any) => block.status === NodesOverviewNodeBlockStatus.FETCHING).length, ledgers: this.getLedgers(node.ledgers), - resyncs: this.getResyncs(node.resyncs), blocks, } as NodesOverviewNode; }); @@ -222,15 +219,4 @@ export class NodesOverviewService { private noneOfStepsCompleted(step: any): boolean { return !step.snarked.fetch_hashes_start && !step.snarked.fetch_accounts_start; } - - private getResyncs(resyncs: any[]): NodesOverviewResync[] { - return resyncs.map((resync: any) => { - const kind = typeof resync.kind === 'string' ? resync.kind : Object.keys(resync.kind)[0]; - return { - kind: kind.replace(/([A-Z])/g, ' $1').trim(), - description: typeof resync.kind === 'string' ? undefined : Object.values(resync.kind)[0]?.toString(), - time: resync.time, - }; - }); - } } diff --git a/frontend/src/app/features/zk/zk.component.html b/frontend/src/app/features/zk/zk.component.html deleted file mode 100644 index 7f6167bb5f..0000000000 --- a/frontend/src/app/features/zk/zk.component.html +++ /dev/null @@ -1 +0,0 @@ -

zk works!

diff --git a/frontend/src/app/features/zk/zk.component.scss b/frontend/src/app/features/zk/zk.component.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/frontend/src/app/features/zk/zk.component.ts b/frontend/src/app/features/zk/zk.component.ts deleted file mode 100644 index 7d03185eed..0000000000 --- a/frontend/src/app/features/zk/zk.component.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; -import { AccountUpdate, Field, method, Mina, PrivateKey, Provable, PublicKey, SmartContract, state, State } from 'o1js'; - -class HelloWorld extends SmartContract {} - - -export class Square extends SmartContract { - @state(Field) num = State(); - - override init() { - super.init(); - this.num.set(Field(3)); - } - - @method - async update(square: Field) { - const currentState = this.num.get(); - this.num.requireEquals(currentState); - square.assertEquals(currentState.mul(currentState)); - this.num.set(square); - } -} - -@Component({ - selector: 'mina-zk', - templateUrl: './zk.component.html', - styleUrls: ['./zk.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class ZkComponent implements OnInit { - - ngOnInit() { - console.log('Start'); - this.startZK(); - console.log('Finish!'); - } - - async startZK() { - - const useProof = false; - - const Local = await Mina.LocalBlockchain({ proofsEnabled: useProof }); - Mina.setActiveInstance(Local); - - const deployerAccount = Local.testAccounts[0]; - const deployerKey = deployerAccount.key; - const senderAccount = Local.testAccounts[1]; - const senderKey = senderAccount.key; -// ---------------------------------------------------- - -// Create a public/private key pair. The public key is your address and where you deploy the zkApp to - const zkAppPrivateKey = PrivateKey.random(); - const zkAppAddress = zkAppPrivateKey.toPublicKey(); - -// create an instance of Square - and deploy it to zkAppAddress - const zkAppInstance = new Square(zkAppAddress); - const deployTxn = await Mina.transaction(deployerAccount, async () => { - AccountUpdate.fundNewAccount(deployerAccount); - await zkAppInstance.deploy(); - }); - await deployTxn.sign([deployerKey, zkAppPrivateKey]).send(); - -// get the initial state of Square after deployment - const num0 = zkAppInstance.num.get(); - console.log('state after init:', num0.toString()); - -// ---------------------------------------------------- - - const txn1 = await Mina.transaction(senderAccount, async () => { - await zkAppInstance.update(Field(9)); - }); - await txn1.prove(); - await txn1.sign([senderKey]).send(); - - const num1 = zkAppInstance.num.get(); - console.log('state after txn1:', num1.toString()); - -// ---------------------------------------------------- - - try { - const txn2 = await Mina.transaction(senderAccount, async () => { - await zkAppInstance.update(Field(75)); - }); - await txn2.prove(); - await txn2.sign([senderKey]).send(); - } catch (error: any) { - console.log(error.message); - } - const num2 = zkAppInstance.num.get(); - console.log('state after txn2:', num2.toString()); - -// ---------------------------------------------------- - - const txn3 = await Mina.transaction(senderAccount, async () => { - await zkAppInstance.update(Field(81)); - }); - await txn3.prove(); - await txn3.sign([senderKey]).send(); - - const num3 = zkAppInstance.num.get(); - console.log('state after txn3:', num3.toString()); - } -} diff --git a/frontend/src/app/features/zk/zk.module.ts b/frontend/src/app/features/zk/zk.module.ts deleted file mode 100644 index 404533b538..0000000000 --- a/frontend/src/app/features/zk/zk.module.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { ZkComponent } from './zk.component'; -import { RouterModule } from '@angular/router'; -import { ZKRouting } from '@app/features/zk/zk.routing'; - - -@NgModule({ - declarations: [ - ZkComponent, - ], - imports: [ - CommonModule, - ZKRouting, - ], -}) -export class ZkModule {} diff --git a/frontend/src/app/features/zk/zk.routing.ts b/frontend/src/app/features/zk/zk.routing.ts deleted file mode 100644 index aa2bd5d0b6..0000000000 --- a/frontend/src/app/features/zk/zk.routing.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { NgModule } from '@angular/core'; -import { RouterModule, Routes } from '@angular/router'; -import { STATE_TITLE } from '@app/app.routing'; -import { StateComponent } from '@app/features/state/state.component'; -import { ZkComponent } from '@app/features/zk/zk.component'; - -const routes: Routes = [ - { - path: '', - component: ZkComponent, - }, - { - path: '**', - redirectTo: '', - pathMatch: 'full', - }, -]; - -@NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule], -}) -export class ZKRouting {} diff --git a/frontend/src/app/layout/node-picker/node-picker.component.ts b/frontend/src/app/layout/node-picker/node-picker.component.ts index 203c360fad..1568e2fbf1 100644 --- a/frontend/src/app/layout/node-picker/node-picker.component.ts +++ b/frontend/src/app/layout/node-picker/node-picker.component.ts @@ -82,7 +82,6 @@ export class NodePickerComponent extends StoreDispatcher implements AfterViewIni } if (node.isWebNode) { this.webNodeService.webNodeState = 'loading'; - this.router.navigate(['web-node']); } } diff --git a/frontend/src/app/shared/constants/config.ts b/frontend/src/app/shared/constants/config.ts index 8e5c87cd18..6c27b2e5e9 100644 --- a/frontend/src/app/shared/constants/config.ts +++ b/frontend/src/app/shared/constants/config.ts @@ -4,6 +4,10 @@ import { hasValue } from '@openmina/shared'; export const CONFIG: Readonly = { ...environment, + globalConfig: { + ...environment.globalConfig, + graphQL: getURL(environment.globalConfig.graphQL), + }, configs: environment.configs.map((config) => ({ ...config, url: getURL(config.url), diff --git a/frontend/src/app/shared/types/core/environment/mina-env.type.ts b/frontend/src/app/shared/types/core/environment/mina-env.type.ts index c1e529f71e..7d6cb73d38 100644 --- a/frontend/src/app/shared/types/core/environment/mina-env.type.ts +++ b/frontend/src/app/shared/types/core/environment/mina-env.type.ts @@ -2,6 +2,7 @@ export interface MinaEnv { production: boolean; configs: MinaNode[]; identifier?: string; + webNodeKey?: string; hideToolbar?: boolean; hideNodeStats?: boolean; globalConfig?: { diff --git a/frontend/src/app/shared/types/nodes/dashboard/nodes-overview-node.type.ts b/frontend/src/app/shared/types/nodes/dashboard/nodes-overview-node.type.ts index 56a28a0323..4dac6fff9b 100644 --- a/frontend/src/app/shared/types/nodes/dashboard/nodes-overview-node.type.ts +++ b/frontend/src/app/shared/types/nodes/dashboard/nodes-overview-node.type.ts @@ -1,6 +1,5 @@ import { NodesOverviewLedger } from '@shared/types/nodes/dashboard/nodes-overview-ledger.type'; import { NodesOverviewBlock } from '@shared/types/nodes/dashboard/nodes-overview-block.type'; -import { NodesOverviewResync } from '@shared/types/nodes/dashboard/nodes-overview-resync.type'; export interface NodesOverviewNode { name: string; @@ -18,7 +17,6 @@ export interface NodesOverviewNode { fetchingBlocks: number; fetchedBlocks: number; ledgers: NodesOverviewLedger; - resyncs: NodesOverviewResync[]; blocks: NodesOverviewBlock[]; } diff --git a/frontend/src/app/shared/types/nodes/dashboard/nodes-overview-resync.type.ts b/frontend/src/app/shared/types/nodes/dashboard/nodes-overview-resync.type.ts deleted file mode 100644 index 1dc3fea415..0000000000 --- a/frontend/src/app/shared/types/nodes/dashboard/nodes-overview-resync.type.ts +++ /dev/null @@ -1,16 +0,0 @@ -export interface NodesOverviewResync { - kind: NodesOverviewResyncKindType; - time: number; - description?: string; -} - -export enum NodesOverviewResyncKindType { - RootLedgerChange = 'Root Ledger Change', - FetchStagedLedgerError = 'Fetch Staged Ledger Error', - EpochChange = 'Epoch Change', - BestChainChange = 'Best Chain Change', -} - -export interface NodesOverviewResyncUI extends NodesOverviewResync { - timeAgo: string; -} diff --git a/frontend/src/assets/environments/block_producers.js b/frontend/src/assets/environments/block_producers.js index fa5e5b493a..bbb420c066 100644 --- a/frontend/src/assets/environments/block_producers.js +++ b/frontend/src/assets/environments/block_producers.js @@ -8,6 +8,7 @@ export default { 'snarks': ['scan-state', 'work-pool'], }, canAddNodes: true, + graphQL: 'http://localhost:11010/graphql', }, configs: [ { diff --git a/frontend/src/assets/environments/compose.js b/frontend/src/assets/environments/compose.js index 520821fdaa..0f9f93ab6f 100644 --- a/frontend/src/assets/environments/compose.js +++ b/frontend/src/assets/environments/compose.js @@ -8,8 +8,10 @@ export default { state: ['actions'], network: ['node-dht', 'graph-overview', 'bootstrap-stats'], snarks: ['scan-state'], + benchmarks: ['wallets'], }, canAddNodes: true, + graphQL: '/openmina-node/graphql', }, configs: [ { diff --git a/frontend/src/assets/environments/staging.js b/frontend/src/assets/environments/staging.js index 2e971151a8..6c49290a6b 100644 --- a/frontend/src/assets/environments/staging.js +++ b/frontend/src/assets/environments/staging.js @@ -11,7 +11,7 @@ export default { 'benchmarks': ['wallets'], }, canAddNodes: false, - graphQL: 'http://adonagy.hz.minaprotocol.network:3000/graphql' + graphQL: 'https://adonagy.com/graphql' }, configs: [ { diff --git a/frontend/src/assets/o1js/.babelrc b/frontend/src/assets/o1js/.babelrc new file mode 100644 index 0000000000..8aa924d7c6 --- /dev/null +++ b/frontend/src/assets/o1js/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["@babel/preset-env"] +} \ No newline at end of file diff --git a/frontend/src/assets/o1js/.gitignore b/frontend/src/assets/o1js/.gitignore new file mode 100644 index 0000000000..a61d2f8bb7 --- /dev/null +++ b/frontend/src/assets/o1js/.gitignore @@ -0,0 +1,3 @@ +#.gitignore +node_modules +npm-debug.log \ No newline at end of file diff --git a/frontend/src/assets/o1js/babel.config.json b/frontend/src/assets/o1js/babel.config.json new file mode 100644 index 0000000000..fad0e0da59 --- /dev/null +++ b/frontend/src/assets/o1js/babel.config.json @@ -0,0 +1,3 @@ +module.exports = { + presets: ["@babel/preset-env"], +}; \ No newline at end of file diff --git a/frontend/src/assets/o1js/bootstrap.js b/frontend/src/assets/o1js/bootstrap.js new file mode 100644 index 0000000000..0e1b6a758c --- /dev/null +++ b/frontend/src/assets/o1js/bootstrap.js @@ -0,0 +1,3 @@ +import * as index from "./src/index.ts"; + +export default index; diff --git a/frontend/src/assets/o1js/coi-serviceworker.js b/frontend/src/assets/o1js/coi-serviceworker.js new file mode 100644 index 0000000000..28c9266e9a --- /dev/null +++ b/frontend/src/assets/o1js/coi-serviceworker.js @@ -0,0 +1,114 @@ +let coepCredentialless = false; +if (typeof window === 'undefined') { + self.addEventListener("install", () => self.skipWaiting()); + self.addEventListener("activate", (event) => event.waitUntil(self.clients.claim())); + + self.addEventListener("message", (ev) => { + if (!ev.data) { + return; + } else if (ev.data.type === "deregister") { + self.registration + .unregister() + .then(() => { + return self.clients.matchAll(); + }) + .then(clients => { + clients.forEach((client) => client.navigate(client.url)); + }); + } else if (ev.data.type === "coepCredentialless") { + coepCredentialless = ev.data.value; + } + }); + + self.addEventListener("fetch", function (event) { + const r = event.request; + if (r.cache === "only-if-cached" && r.mode !== "same-origin") { + return; + } + + const request = (coepCredentialless && r.mode === "no-cors") + ? new Request(r, { + credentials: "omit", + }) + : r; + event.respondWith( + fetch(request) + .then((response) => { + if (response.status === 0) { + return response; + } + + const newHeaders = new Headers(response.headers); + newHeaders.set("Cross-Origin-Embedder-Policy", + coepCredentialless ? "credentialless" : "require-corp" + ); + newHeaders.set("Cross-Origin-Opener-Policy", "same-origin"); + + return new Response(response.body, { + status: response.status, + statusText: response.statusText, + headers: newHeaders, + }); + }) + .catch((e) => console.error(e)) + ); + }); + +} else { + (() => { + // You can customize the behavior of this script through a global `coi` variable. + const coi = { + shouldRegister: () => true, + shouldDeregister: () => false, + coepCredentialless: () => false, + doReload: () => window.location.reload(), + quiet: false, + ...window.coi + }; + + const n = navigator; + + if (n.serviceWorker && n.serviceWorker.controller) { + n.serviceWorker.controller.postMessage({ + type: "coepCredentialless", + value: coi.coepCredentialless(), + }); + + if (coi.shouldDeregister()) { + n.serviceWorker.controller.postMessage({type: "deregister"}); + } + } + + // If we're already coi: do nothing. Perhaps it's due to this script doing its job, or COOP/COEP are + // already set from the origin server. Also if the browser has no notion of crossOriginIsolated, just give up here. + if (window.crossOriginIsolated !== false || !coi.shouldRegister()) return; + + if (!window.isSecureContext) { + !coi.quiet && console.log("COOP/COEP Service Worker not registered, a secure context is required."); + return; + } + + // In some environments (e.g. Chrome incognito mode) this won't be available + if (n.serviceWorker) { + n.serviceWorker.register(window.document.currentScript.src).then( + (registration) => { + !coi.quiet && console.log("COOP/COEP Service Worker registered", registration.scope); + + registration.addEventListener("updatefound", () => { + !coi.quiet && console.log("Reloading page to make use of updated COOP/COEP Service Worker."); + coi.doReload(); + }); + + // If the registration is active, but it's not controlling the page + if (registration.active && !n.serviceWorker.controller) { + !coi.quiet && console.log("Reloading page to make use of COOP/COEP Service Worker."); + coi.doReload(); + } + }, + (err) => { + !coi.quiet && console.error("COOP/COEP Service Worker failed to register:", err); + } + ); + } + })(); +} diff --git a/frontend/src/assets/o1js/o1jsWrapper.js b/frontend/src/assets/o1js/dist/o1js-wrapper.js similarity index 99% rename from frontend/src/assets/o1js/o1jsWrapper.js rename to frontend/src/assets/o1js/dist/o1js-wrapper.js index 91ddab58f1..ffa812513a 100644 --- a/frontend/src/assets/o1js/o1jsWrapper.js +++ b/frontend/src/assets/o1js/dist/o1js-wrapper.js @@ -26,7 +26,7 @@ return /******/ (() => { // webpackBootstrap \**********************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _src_index_ts__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./src/index.ts */ \"./src/index.ts\");\n// import(\"./coi-serviceworker.js\");\n// import(\"./src/index.ts\");\n\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_src_index_ts__WEBPACK_IMPORTED_MODULE_0__);\n\n//# sourceURL=webpack://o1jsWrapper/./bootstrap.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _src_index_ts__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./src/index.ts */ \"./src/index.ts\");\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_src_index_ts__WEBPACK_IMPORTED_MODULE_0__);\n\n//# sourceURL=webpack://o1jsWrapper/./bootstrap.js?"); /***/ }), @@ -36,17 +36,17 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac \**********************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ sendZkApp: () => (/* reexport safe */ _tutorial_gql4_run__WEBPACK_IMPORTED_MODULE_0__.sendZkApp)\n/* harmony export */ });\n/* harmony import */ var _tutorial_gql4_run__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./tutorial-gql4/run */ \"./src/tutorial-gql4/run.ts\");\n// import { runTutorial2 } from './tutorial2/run';\n// import { runTutorialGql } from './tutorial-gql/run';\n// import { runTutorial3 } from './tutorial3/run';\n// import { gql2deploy, gql2update } from './tutorial-gql2/run';\n// import { gql3 } from './tutorial-gql3/run';\n\n// document.getElementById('tutorial2').onclick = () => runTutorial2();\n// document.getElementById('tutorial3').onclick = () => runTutorial3();\n// document.getElementById('tutorialgql').onclick = () => runTutorialGql();\n// document.getElementById('gql2deploy').onclick = () => gql2deploy();\n// document.getElementById('gql2update').onclick = () => gql2update();\n// document.getElementById('gql3').onclick = () => gql3();\n// document.getElementById('gql4').onclick = () => sendZkApp('https://api.minascan.io/node/devnet/v1/graphql',{\n// \t\"payerPublicKey\": \"B62qqLJ26MuC2pAnEYAW8dKdno8YVXY1boB9cDWqepp9q8FtRMbj8Jj\",\n// \t\"payerPrivateKey\": \"EKDk2KzzBcgUz63P9mNUEGD9siSiSfdyh6byu4bBsmhYXtpdmK3T\",\n// \t\"fee\": 0.001,\n// \t\"nonce\": \"21\",\n// \t\"memo\": \"S.T.1727429279075,1,328909544\",\n// \t\"accountUpdates\": 1\n// },{next: (val: string) => console.log(val)});\n// export {\n// \tgql2deploy,\n// \tgql2update,\n// \tzkAppKeys,\n// }\n\n\n\n//# sourceURL=webpack://o1jsWrapper/./src/index.ts?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ deployZkApp: () => (/* reexport safe */ _zk_app_zk_app__WEBPACK_IMPORTED_MODULE_0__.deployZkApp),\n/* harmony export */ updateZkApp: () => (/* reexport safe */ _zk_app_zk_app__WEBPACK_IMPORTED_MODULE_0__.updateZkApp)\n/* harmony export */ });\n/* harmony import */ var _zk_app_zk_app__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./zk-app/zk-app */ \"./src/zk-app/zk-app.ts\");\n\n\n\n\n//# sourceURL=webpack://o1jsWrapper/./src/index.ts?"); /***/ }), -/***/ "./src/tutorial-gql4/run.ts": -/*!**********************************!*\ - !*** ./src/tutorial-gql4/run.ts ***! - \**********************************/ +/***/ "./src/zk-app/zk-app.ts": +/*!******************************!*\ + !*** ./src/zk-app/zk-app.ts ***! + \******************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ gql4: () => (/* binding */ gql4),\n/* harmony export */ sendZkApp: () => (/* binding */ sendZkApp)\n/* harmony export */ });\n/* harmony import */ var o1js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! o1js */ \"./node_modules/o1js/dist/web/index.js\");\nvar __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n return c > 3 && r && Object.defineProperty(target, key, r), r;\n};\nvar __metadata = (undefined && undefined.__metadata) || function (k, v) {\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(k, v);\n};\n\nclass Add extends o1js__WEBPACK_IMPORTED_MODULE_0__.SmartContract {\n constructor() {\n super(...arguments);\n this.num = (0,o1js__WEBPACK_IMPORTED_MODULE_0__.State)();\n }\n init() {\n this.account.provedState.requireEquals(this.account.provedState.get());\n this.account.provedState.get().assertFalse();\n super.init();\n this.num.set((0,o1js__WEBPACK_IMPORTED_MODULE_0__.Field)(1));\n }\n async update() {\n const currentState = this.num.getAndRequireEquals();\n const newState = currentState.add(5);\n this.num.set(newState);\n }\n async deploy() {\n super.deploy();\n this.account.permissions.set({\n ...o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.default(),\n setVerificationKey: {\n txnVersion: o1js__WEBPACK_IMPORTED_MODULE_0__.TransactionVersion.current(),\n auth: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.proof(),\n },\n setDelegate: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.proof(),\n setPermissions: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.proof(),\n setZkappUri: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.proof(),\n setTokenSymbol: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.proof(),\n incrementNonce: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.proof(),\n setVotingFor: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.proof(),\n setTiming: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.proof(),\n send: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.proof(),\n editState: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.proof(),\n receive: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.proof(),\n access: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.proof(),\n editActionState: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.proof(),\n });\n }\n}\n__decorate([\n (0,o1js__WEBPACK_IMPORTED_MODULE_0__.state)(o1js__WEBPACK_IMPORTED_MODULE_0__.Field),\n __metadata(\"design:type\", Object)\n], Add.prototype, \"num\", void 0);\n__decorate([\n o1js__WEBPACK_IMPORTED_MODULE_0__.method,\n __metadata(\"design:type\", Function),\n __metadata(\"design:paramtypes\", []),\n __metadata(\"design:returntype\", Promise)\n], Add.prototype, \"update\", null);\nclass IsEven extends o1js__WEBPACK_IMPORTED_MODULE_0__.SmartContract {\n constructor() {\n super(...arguments);\n this.number = (0,o1js__WEBPACK_IMPORTED_MODULE_0__.State)();\n }\n // Initialize the zkApp with a number\n init() {\n super.init();\n this.number.set((0,o1js__WEBPACK_IMPORTED_MODULE_0__.Field)(10));\n }\n // Method to check if the number is even\n async checkEven() {\n this.number.requireEquals(this.number.get());\n const num = this.number.get();\n const isEven = num.isEven();\n this.generateProof(isEven);\n }\n // Generate a proof for the computation\n generateProof(isEven) {\n const hash = o1js__WEBPACK_IMPORTED_MODULE_0__.Poseidon.hash([this.number.get()]);\n o1js__WEBPACK_IMPORTED_MODULE_0__.Provable.log(hash, isEven);\n }\n async deploy() {\n super.deploy();\n this.account.permissions.set({\n ...o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.default(),\n setVerificationKey: {\n txnVersion: o1js__WEBPACK_IMPORTED_MODULE_0__.TransactionVersion.current(),\n auth: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.proof(),\n },\n setDelegate: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.proof(),\n setPermissions: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.proof(),\n setZkappUri: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.proof(),\n setTokenSymbol: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.proof(),\n incrementNonce: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.proof(),\n setVotingFor: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.proof(),\n setTiming: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.proof(),\n send: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.proof(),\n editState: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.proof(),\n receive: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.proof(),\n access: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.proof(),\n editActionState: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.proof(),\n });\n }\n}\n__decorate([\n (0,o1js__WEBPACK_IMPORTED_MODULE_0__.state)(o1js__WEBPACK_IMPORTED_MODULE_0__.Field),\n __metadata(\"design:type\", Object)\n], IsEven.prototype, \"number\", void 0);\n__decorate([\n o1js__WEBPACK_IMPORTED_MODULE_0__.method,\n __metadata(\"design:type\", Function),\n __metadata(\"design:paramtypes\", []),\n __metadata(\"design:returntype\", Promise)\n], IsEven.prototype, \"checkEven\", null);\nconst wallets = [\n {\n privateKey: 'EKEQGWy4TjbVeqKjbe7TW81DKQM34min5FNmXpKArHKLyGVd3KSP',\n publicKey: 'B62qpD75xH5R19wxZG2uz8whNsHPTioVoYcPV3zfjjSbzTmaHQHKKEV',\n },\n {\n privateKey: 'EKETKywEr7ktbzqj8D2aj4yYZVMyj33sHuWLQydbzt1M3sGnAbTh',\n publicKey: 'B62qnLjgW4LAnrxkcdLc7Snb49qx6aP5qsmPsp6ueZN4XPMC621cqGc',\n },\n];\nconst payerKeys = {\n publicKey: o1js__WEBPACK_IMPORTED_MODULE_0__.PrivateKey.fromBase58(wallets[0].privateKey).toPublicKey(),\n privateKey: o1js__WEBPACK_IMPORTED_MODULE_0__.PrivateKey.fromBase58(wallets[0].privateKey),\n};\nconst zkApps = [];\nfor (let i = 0; i < 2; i++) {\n const randPrivateKey = o1js__WEBPACK_IMPORTED_MODULE_0__.PrivateKey.random();\n zkApps.push({\n publicKey: randPrivateKey.toPublicKey(),\n privateKey: randPrivateKey,\n });\n}\nasync function gql4(graphQlUrl, input) {\n // const network = Mina.Network('http://65.109.105.40:5000/graphql');\n // const network = Mina.Network('https://api.minascan.io/node/devnet/v1/graphql');\n const network = o1js__WEBPACK_IMPORTED_MODULE_0__.Mina.Network('http://adonagy.hz.minaprotocol.network:3000/graphql');\n o1js__WEBPACK_IMPORTED_MODULE_0__.Mina.setActiveInstance(network);\n // const zkAppPublicKey = PublicKey.fromBase58(wallets[1].publicKey);\n // const zkAppPrivateKey = PrivateKey.fromBase58(wallets[1].privateKey);\n // const zks = zkApps.map((zkApp) => new Add(zkApp.publicKey));\n const zk1 = new Add(zkApps[0].publicKey);\n const zk2 = new Add(zkApps[1].publicKey);\n console.log('fetching account...');\n const { account } = await (0,o1js__WEBPACK_IMPORTED_MODULE_0__.fetchAccount)({ publicKey: payerKeys.publicKey });\n console.log(account);\n console.log('Compiling...');\n await Add.compile();\n console.log('Updating...');\n console.log('ZkAPP pub_key:', zkApps[0].publicKey.toBase58(), zkApps[0].privateKey.toBase58());\n console.log('ZkAPP pub_key:', zkApps[1].publicKey.toBase58(), zkApps[1].privateKey.toBase58());\n const payerAccount = { sender: payerKeys.publicKey, fee: Number('0.1') * 1e9, nonce: o1js__WEBPACK_IMPORTED_MODULE_0__.Types.Account.toJSON(account).nonce };\n let tx = await o1js__WEBPACK_IMPORTED_MODULE_0__.Mina.transaction(payerAccount, async () => {\n o1js__WEBPACK_IMPORTED_MODULE_0__.AccountUpdate.fundNewAccount(payerKeys.publicKey, 2);\n console.log('zkApp deploying...');\n await zk1.deploy();\n await zk2.deploy();\n });\n console.log('Proving...');\n await tx.prove();\n console.log('Submitting...');\n await tx.sign([payerKeys.privateKey, zkApps[0].privateKey, zkApps[1].privateKey]);\n await tx.safeSend().then((sentTx) => {\n console.log(sentTx);\n if (sentTx.data) {\n }\n else if (tx?.errors?.length) {\n console.log('Transaction errors: ', tx?.errors[0]);\n console.log(tx?.errors[0].statusText);\n }\n });\n}\nasync function sendZkApp(graphQlUrl, input, updates) {\n console.log('----------- Sending ZkApp -----------');\n const network = o1js__WEBPACK_IMPORTED_MODULE_0__.Mina.Network(graphQlUrl);\n o1js__WEBPACK_IMPORTED_MODULE_0__.Mina.setActiveInstance(network);\n const pairs = Array.from({ length: input.accountUpdates }, () => {\n const randPrivateKey = o1js__WEBPACK_IMPORTED_MODULE_0__.PrivateKey.random();\n return {\n publicKey: randPrivateKey.toPublicKey(),\n privateKey: randPrivateKey,\n };\n });\n const zkApps = pairs.map((pair) => new IsEven(pair.publicKey));\n let stepStartTime = performance.now();\n const updateStep = (step) => {\n const now = performance.now();\n updates.next({ step, duration: now - stepStartTime });\n let duration = (now - stepStartTime) / 1000;\n console.log(`${step} (${Math.round(duration * 10000) / 10000}s)`);\n stepStartTime = now;\n };\n await IsEven.compile();\n updateStep('Compiled');\n const payerAccount = { sender: o1js__WEBPACK_IMPORTED_MODULE_0__.PublicKey.fromBase58(input.payerPublicKey), fee: input.fee * 1e9, nonce: Number(input.nonce), memo: input.memo };\n let tx = await o1js__WEBPACK_IMPORTED_MODULE_0__.Mina.transaction(payerAccount, async () => {\n o1js__WEBPACK_IMPORTED_MODULE_0__.AccountUpdate.fundNewAccount(o1js__WEBPACK_IMPORTED_MODULE_0__.PublicKey.fromBase58(input.payerPublicKey), input.accountUpdates);\n await Promise.all(zkApps.map((zkApp) => zkApp.deploy()));\n });\n updateStep('Deployed');\n await tx.prove();\n updateStep('Proved');\n await tx.sign([o1js__WEBPACK_IMPORTED_MODULE_0__.PrivateKey.fromBase58(input.payerPrivateKey), ...pairs.map((pair) => pair.privateKey)]);\n updateStep('Signed');\n return tx.safeSend().then((sentTx) => {\n updateStep('Sent');\n console.log(sentTx);\n console.log('----------- Done -----------');\n return sentTx;\n });\n}\n\n\n//# sourceURL=webpack://o1jsWrapper/./src/tutorial-gql4/run.ts?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ deployZkApp: () => (/* binding */ deployZkApp),\n/* harmony export */ updateZkApp: () => (/* binding */ updateZkApp)\n/* harmony export */ });\n/* harmony import */ var o1js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! o1js */ \"./node_modules/o1js/dist/web/index.js\");\nvar __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n return c > 3 && r && Object.defineProperty(target, key, r), r;\n};\nvar __metadata = (undefined && undefined.__metadata) || function (k, v) {\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(k, v);\n};\n\nclass Add extends o1js__WEBPACK_IMPORTED_MODULE_0__.SmartContract {\n constructor() {\n super(...arguments);\n this.num = (0,o1js__WEBPACK_IMPORTED_MODULE_0__.State)();\n }\n init() {\n this.account.provedState.requireEquals(this.account.provedState.get());\n this.account.provedState.get().assertFalse();\n super.init();\n this.num.set((0,o1js__WEBPACK_IMPORTED_MODULE_0__.Field)(1));\n }\n async update() {\n const currentState = this.num.getAndRequireEquals();\n const newState = currentState.add(5);\n this.num.set(newState);\n }\n async deploy() {\n super.deploy();\n this.account.permissions.set({\n ...o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.default(),\n setDelegate: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.signature(),\n setPermissions: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.signature(),\n setZkappUri: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.signature(),\n setTokenSymbol: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.signature(),\n incrementNonce: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.signature(),\n setVotingFor: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.signature(),\n setTiming: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.signature(),\n send: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.proof(),\n editState: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.proof(),\n receive: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.none(),\n access: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.none(),\n editActionState: o1js__WEBPACK_IMPORTED_MODULE_0__.Permissions.proof(),\n });\n }\n}\n__decorate([\n (0,o1js__WEBPACK_IMPORTED_MODULE_0__.state)(o1js__WEBPACK_IMPORTED_MODULE_0__.Field),\n __metadata(\"design:type\", Object)\n], Add.prototype, \"num\", void 0);\n__decorate([\n o1js__WEBPACK_IMPORTED_MODULE_0__.method,\n __metadata(\"design:type\", Function),\n __metadata(\"design:paramtypes\", []),\n __metadata(\"design:returntype\", Promise)\n], Add.prototype, \"update\", null);\nasync function deployZkApp(graphQlUrl, input, updates) {\n console.log('----------- Sending ZkApp -----------');\n const network = o1js__WEBPACK_IMPORTED_MODULE_0__.Mina.Network(graphQlUrl);\n o1js__WEBPACK_IMPORTED_MODULE_0__.Mina.setActiveInstance(network);\n const pairs = Array.from({ length: input.accountUpdates }, () => {\n const randPrivateKey = o1js__WEBPACK_IMPORTED_MODULE_0__.PrivateKey.random();\n return {\n publicKey: randPrivateKey.toPublicKey(),\n privateKey: randPrivateKey,\n };\n });\n console.log(pairs.map((pair) => pair.privateKey.toBase58()));\n const zkApps = pairs.map((pair) => new Add(pair.publicKey));\n let stepStartTime = performance.now();\n const updateStep = (step) => {\n const now = performance.now();\n if (step === 'Compiling') {\n updates.next({ step, duration: undefined });\n return;\n }\n let duration = Math.round((now - stepStartTime) / 1000 * 1000) / 1000;\n updates.next({ step, duration });\n console.log(`${step} (${duration}s)`);\n stepStartTime = now;\n };\n updateStep('Compiling');\n await Add.compile();\n updateStep('Compiled');\n const payerAccount = {\n sender: o1js__WEBPACK_IMPORTED_MODULE_0__.PublicKey.fromBase58(input.payerPublicKey),\n fee: input.fee * 1e9,\n nonce: Number(input.nonce),\n memo: input.memo,\n };\n let tx = await o1js__WEBPACK_IMPORTED_MODULE_0__.Mina.transaction(payerAccount, async () => {\n o1js__WEBPACK_IMPORTED_MODULE_0__.AccountUpdate.fundNewAccount(o1js__WEBPACK_IMPORTED_MODULE_0__.PublicKey.fromBase58(input.payerPublicKey), input.accountUpdates);\n for (const zkApp of zkApps) {\n await zkApp.deploy();\n }\n });\n updateStep('Deployed');\n await tx.prove();\n updateStep('Proved');\n await tx.sign([o1js__WEBPACK_IMPORTED_MODULE_0__.PrivateKey.fromBase58(input.payerPrivateKey), ...pairs.map((pair) => pair.privateKey)]);\n updateStep('Signed');\n return tx.safeSend().then((sentTx) => {\n updateStep('Sent');\n console.log(sentTx);\n console.log('----------- Done -----------');\n return sentTx;\n });\n}\nconst deployedZkApps = [\n 'EKEbTHeqQbq5zeFuspjVSoatEebrG7fJnz8CrXyP4aVAXzeD1Z6A',\n 'EKFF1zZ4KUCZoe7GXHAPcfLdkGPgsYJ5RNtQvHMx8ndhY1pZttaa',\n];\nasync function updateZkApp(graphQlUrl, input, updates) {\n console.log('----------- Updating ZkApp -----------');\n const network = o1js__WEBPACK_IMPORTED_MODULE_0__.Mina.Network(graphQlUrl);\n o1js__WEBPACK_IMPORTED_MODULE_0__.Mina.setActiveInstance(network);\n const pairs = Array.from({ length: input.accountUpdates }, (_, i) => {\n const randPrivateKey = o1js__WEBPACK_IMPORTED_MODULE_0__.PrivateKey.fromBase58(deployedZkApps[i]);\n return {\n publicKey: randPrivateKey.toPublicKey(),\n privateKey: randPrivateKey,\n };\n });\n const zkApps = pairs.map((pair) => new Add(pair.publicKey));\n let stepStartTime = performance.now();\n const updateStep = (step) => {\n const now = performance.now();\n if (step === 'Compiling') {\n updates.next({ step, duration: undefined });\n return;\n }\n let duration = Math.round((now - stepStartTime) / 1000 * 1000) / 1000;\n updates.next({ step, duration });\n console.log(`${step} (${duration}s)`);\n stepStartTime = now;\n };\n updateStep('Compiling');\n await Add.compile();\n updateStep('Compiled');\n const payerAccount = {\n sender: o1js__WEBPACK_IMPORTED_MODULE_0__.PublicKey.fromBase58(input.payerPublicKey),\n fee: input.fee * 1e9,\n nonce: Number(input.nonce),\n memo: input.memo,\n };\n let tx = await o1js__WEBPACK_IMPORTED_MODULE_0__.Mina.transaction(payerAccount, async () => {\n for (const zkApp of zkApps) {\n await zkApp.update();\n }\n });\n updateStep('Proved Check Even');\n await tx.prove();\n updateStep('Proved');\n await tx.sign([o1js__WEBPACK_IMPORTED_MODULE_0__.PrivateKey.fromBase58(input.payerPrivateKey), ...pairs.map((pair) => pair.privateKey)]);\n updateStep('Signed');\n return tx.safeSend().then((sentTx) => {\n updateStep('Sent');\n updateStep(null);\n console.log(sentTx);\n console.log('----------- Done -----------');\n return sentTx;\n });\n}\n\n\n//# sourceURL=webpack://o1jsWrapper/./src/zk-app/zk-app.ts?"); /***/ }), diff --git a/frontend/src/assets/o1js/package-lock.json b/frontend/src/assets/o1js/package-lock.json new file mode 100644 index 0000000000..8e96afd8ac --- /dev/null +++ b/frontend/src/assets/o1js/package-lock.json @@ -0,0 +1,11130 @@ +{ + "name": "my-webpack-app2", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "my-webpack-app2", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "bs58": "^5.0.0", + "byteify": "^4.1.4", + "css-loader": "^6.8.1", + "express": "^4.21.0", + "o1js": "1.8.0", + "script-loader": "^0.7.2", + "style-loader": "^3.3.3" + }, + "devDependencies": { + "@babel/core": "^7.25.2", + "@babel/preset-env": "^7.25.4", + "babel-loader": "^9.2.1", + "copy-webpack-plugin": "^11.0.0", + "ts-loader": "^9.4.4", + "typescript": "^5.2.2", + "webpack": "^5.94.0", + "webpack-cli": "^5.1.4", + "webpack-dev-server": "^4.15.1" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.4.tgz", + "integrity": "sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/core/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.6.tgz", + "integrity": "sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.25.6", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", + "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz", + "integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", + "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.25.2", + "@babel/helper-validator-option": "^7.24.8", + "browserslist": "^4.23.1", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.4.tgz", + "integrity": "sha512-ro/bFs3/84MDgDmMwbcHgDa8/E6J3QKNTk4xJJnVeFtGE+tL0K26E3pNxhYz2b67fJpt7Aphw5XcploKXuCvCQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-member-expression-to-functions": "^7.24.8", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/helper-replace-supers": "^7.25.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/traverse": "^7.25.4", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.2.tgz", + "integrity": "sha512-+wqVGP+DFmqwFD3EH6TMTfUNeqDehV3E/dl+Sd54eaXqm17tEUNbEIn4sVivVowbvUpOtIGxdo3GoXyDH9N/9g==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", + "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", + "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.24.8", + "@babel/types": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", + "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", + "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", + "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.0.tgz", + "integrity": "sha512-NhavI2eWEIz/H9dbrG0TuOicDhNexze43i5z7lEqwYm0WEZVTwnPpA0EafUTP7+6/W79HWIP2cTe3Z5NiSTVpw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-wrap-function": "^7.25.0", + "@babel/traverse": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.0.tgz", + "integrity": "sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg==", + "dev": true, + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.24.8", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/traverse": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", + "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", + "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.0.tgz", + "integrity": "sha512-s6Q1ebqutSiZnEjaofc/UKDyC4SbzV5n5SrA2Gq8UawLycr3i04f1dX4OzoQVnexm6aOCh37SQNYlJ/8Ku+PMQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.0", + "@babel/types": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.6.tgz", + "integrity": "sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==", + "dev": true, + "dependencies": { + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.6.tgz", + "integrity": "sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.25.6" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.3.tgz", + "integrity": "sha512-wUrcsxZg6rqBXG05HG1FPYgsP6EvwF4WpBbxIpWIIYnH8wG0gzx3yZY3dtEHas4sTAOGkbTsc9EGPxwff8lRoA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.0.tgz", + "integrity": "sha512-Bm4bH2qsX880b/3ziJ8KD711LT7z4u8CFudmjqle65AZj/HNUFhEf90dqYv6O86buWvSBmeQDjv0Tn2aF/bIBA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.0.tgz", + "integrity": "sha512-lXwdNZtTmeVOOFtwM/WDe7yg1PL8sYhRk/XH0FzbR2HDQ0xC+EnQ/JHeoMYSavtU115tnUk0q9CDyq8si+LMAA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz", + "integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.0.tgz", + "integrity": "sha512-tggFrk1AIShG/RUQbEwt2Tr/E+ObkfwrPjR6BjbRvsx24+PSjK8zrq0GWPNCjo8qpRx4DuJzlcvWJqlm+0h3kw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.25.6.tgz", + "integrity": "sha512-aABl0jHw9bZ2karQ/uUD6XP4u0SG22SJrOHFoL6XB1R7dTovOP4TzTlsxOYC5yQ1pdscVK2JTUnF6QL3ARoAiQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.6.tgz", + "integrity": "sha512-sXaDXaJN9SNLymBdlWFA+bjzBhFD617ZaFiY13dGt7TVslVvVgA6fkZOP7Ki3IGElC45lwHdOTrCtKZGVAWeLQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz", + "integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.4.tgz", + "integrity": "sha512-jz8cV2XDDTqjKPwVPJBIjORVEmSGYhdRa8e5k5+vN+uwcjSrSxUaebBRa4ko1jqNF2uxyg8G6XYk30Jv285xzg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-remap-async-to-generator": "^7.25.0", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/traverse": "^7.25.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz", + "integrity": "sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-remap-async-to-generator": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz", + "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.0.tgz", + "integrity": "sha512-yBQjYoOjXlFv9nlXb3f1casSHOZkWr29NX+zChVanLg5Nc157CrbEX9D7hxxtTpuFy7Q0YzmmWfJxzvps4kXrQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.4.tgz", + "integrity": "sha512-nZeZHyCWPfjkdU5pA/uHiTaDAFUEqkpzf1YoQT2NeSynCGYq9rxfyI3XpQbfx/a0hSnFH6TGlEXvae5Vi7GD8g==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.4", + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz", + "integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.4.tgz", + "integrity": "sha512-oexUfaQle2pF/b6E0dwsxQtAol9TLSO88kQvym6HHBWFliV2lGdrPieX+WgMRLSJDVzdYywk7jXbLPuO2KLTLg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-replace-supers": "^7.25.0", + "@babel/traverse": "^7.25.4", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", + "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/template": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.8.tgz", + "integrity": "sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz", + "integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz", + "integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.0.tgz", + "integrity": "sha512-YLpb4LlYSc3sCUa35un84poXoraOiQucUTTu8X1j18JV+gNa8E0nyUf/CjZ171IRGr4jEguF+vzJU66QZhn29g==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", + "integrity": "sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz", + "integrity": "sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz", + "integrity": "sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz", + "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.25.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.1.tgz", + "integrity": "sha512-TVVJVdW9RKMNgJJlLtHsKDTydjZAbwIsn6ySBPQaEAUU5+gVvlJt/9nRmqVbsV/IBanRjzWoaAQKLoamWVOUuA==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz", + "integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.2.tgz", + "integrity": "sha512-HQI+HcTbm9ur3Z2DkO+jgESMAMcYLuN/A7NRw9juzxAezN9AvqvUTnpKP/9kkYANz6u7dFlAyOu44ejuGySlfw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz", + "integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz", + "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz", + "integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz", + "integrity": "sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-simple-access": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.0.tgz", + "integrity": "sha512-YPJfjQPDXxyQWg/0+jHKj1llnY5f/R6a0p/vP4lPymxLu7Lvl4k2WMitqi08yxwQcCVUUdG9LCUj4TNEgAp3Jw==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz", + "integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz", + "integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz", + "integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz", + "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz", + "integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz", + "integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz", + "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz", + "integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz", + "integrity": "sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz", + "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.4.tgz", + "integrity": "sha512-ao8BG7E2b/URaUQGqN3Tlsg+M3KlHY6rJ1O1gXAEUnZoyNQnvKyH87Kfg+FoxSeyWUB8ISZZsC91C44ZuBFytw==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.4", + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz", + "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz", + "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz", + "integrity": "sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz", + "integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz", + "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz", + "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz", + "integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", + "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz", + "integrity": "sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz", + "integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz", + "integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz", + "integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.4.tgz", + "integrity": "sha512-qesBxiWkgN1Q+31xUE9RcMk79eOXXDCv6tfyGMRSs4RGlioSg2WVyQAm07k726cSE56pa+Kb0y9epX2qaXzTvA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.4.tgz", + "integrity": "sha512-W9Gyo+KmcxjGahtt3t9fb14vFRWvPpu5pT6GBlovAK6BTBcxgjfVMSQCfJl4oi35ODrxP6xx2Wr8LNST57Mraw==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.25.4", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-validator-option": "^7.24.8", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.3", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.0", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.0", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.0", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.24.7", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.24.7", + "@babel/plugin-transform-async-generator-functions": "^7.25.4", + "@babel/plugin-transform-async-to-generator": "^7.24.7", + "@babel/plugin-transform-block-scoped-functions": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.25.0", + "@babel/plugin-transform-class-properties": "^7.25.4", + "@babel/plugin-transform-class-static-block": "^7.24.7", + "@babel/plugin-transform-classes": "^7.25.4", + "@babel/plugin-transform-computed-properties": "^7.24.7", + "@babel/plugin-transform-destructuring": "^7.24.8", + "@babel/plugin-transform-dotall-regex": "^7.24.7", + "@babel/plugin-transform-duplicate-keys": "^7.24.7", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.0", + "@babel/plugin-transform-dynamic-import": "^7.24.7", + "@babel/plugin-transform-exponentiation-operator": "^7.24.7", + "@babel/plugin-transform-export-namespace-from": "^7.24.7", + "@babel/plugin-transform-for-of": "^7.24.7", + "@babel/plugin-transform-function-name": "^7.25.1", + "@babel/plugin-transform-json-strings": "^7.24.7", + "@babel/plugin-transform-literals": "^7.25.2", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", + "@babel/plugin-transform-member-expression-literals": "^7.24.7", + "@babel/plugin-transform-modules-amd": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.8", + "@babel/plugin-transform-modules-systemjs": "^7.25.0", + "@babel/plugin-transform-modules-umd": "^7.24.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", + "@babel/plugin-transform-new-target": "^7.24.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", + "@babel/plugin-transform-numeric-separator": "^7.24.7", + "@babel/plugin-transform-object-rest-spread": "^7.24.7", + "@babel/plugin-transform-object-super": "^7.24.7", + "@babel/plugin-transform-optional-catch-binding": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.8", + "@babel/plugin-transform-parameters": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.25.4", + "@babel/plugin-transform-private-property-in-object": "^7.24.7", + "@babel/plugin-transform-property-literals": "^7.24.7", + "@babel/plugin-transform-regenerator": "^7.24.7", + "@babel/plugin-transform-reserved-words": "^7.24.7", + "@babel/plugin-transform-shorthand-properties": "^7.24.7", + "@babel/plugin-transform-spread": "^7.24.7", + "@babel/plugin-transform-sticky-regex": "^7.24.7", + "@babel/plugin-transform-template-literals": "^7.24.7", + "@babel/plugin-transform-typeof-symbol": "^7.24.8", + "@babel/plugin-transform-unicode-escapes": "^7.24.7", + "@babel/plugin-transform-unicode-property-regex": "^7.24.7", + "@babel/plugin-transform-unicode-regex": "^7.24.7", + "@babel/plugin-transform-unicode-sets-regex": "^7.25.4", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.6", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.37.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", + "dev": true + }, + "node_modules/@babel/runtime": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.6.tgz", + "integrity": "sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", + "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.25.0", + "@babel/types": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.6.tgz", + "integrity": "sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.6", + "@babel/parser": "^7.25.6", + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.6", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/traverse/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@babel/types": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.6.tgz", + "integrity": "sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", + "dev": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.3", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.3.tgz", + "integrity": "sha512-oyl4jvAfTGX9Bt6Or4H9ni1Z447/tQuxnZsytsCaExKlmJiU8sFgnIBRzJUpKwB5eWn9HuBYlUlVA74q/yN0eQ==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.11", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.11.tgz", + "integrity": "sha512-isGhjmBtLIxdHBDl2xGwUzEM8AOyOvWsADWq7rqirdi/ZQoHnLWErHvsThcEzTX8juDRiZtzp2Qkv5bgNh6mAg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.36", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.36.tgz", + "integrity": "sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.1.tgz", + "integrity": "sha512-iaQslNbARe8fctL5Lk+DsmgWOM83lM+7FzP0eQUJs1jd3kBE8NWqBTIT2S8SqQOJjxvt2eyIjpOuYeRXq2AdMw==", + "dev": true, + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==" + }, + "node_modules/@types/express": { + "version": "4.17.18", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.18.tgz", + "integrity": "sha512-Sxv8BSLLgsBYmcnGdGjjEjqET2U+AKAdCRODmMiq02FgjwuV75Ut85DRpvFjyw/Mk0vgUOliGRU0UUmuuZHByQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.37", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.37.tgz", + "integrity": "sha512-ZohaCYTgGFcOP7u6aJOhY9uIZQgZ2vxC2yWoArY+FeDXlqeH66ZVBjgvg+RLVAS/DWNq4Ap9ZXu1+SUQiiWYMg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.2.tgz", + "integrity": "sha512-lPG6KlZs88gef6aD85z3HNkztpj7w2R7HmR3gygjfXCQmsLloWNARFkMuzKiiY8FGdh1XDpgBdrSf4aKDiA7Kg==", + "dev": true + }, + "node_modules/@types/http-proxy": { + "version": "1.17.12", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.12.tgz", + "integrity": "sha512-kQtujO08dVtQ2wXAuSFfk9ASy3sug4+ogFR8Kd8UgP8PEuc1/G/8yjYRmp//PcDNJEUKOza/MrQu15bouEUCiw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.13", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz", + "integrity": "sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==" + }, + "node_modules/@types/mime": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.3.tgz", + "integrity": "sha512-Ys+/St+2VF4+xuY6+kDIXGxbNRO0mesVg0bbxEfB97Od1Vjpjx9KD1qxs64Gcb3CWPirk9Xe+PT4YiiHQ9T+eg==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.7.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.7.1.tgz", + "integrity": "sha512-LT+OIXpp2kj4E2S/p91BMe+VgGX2+lfO+XTpfXhh+bCk2LkQtHZSub8ewFBMGP5ClysPjTDFa4sMI8Q3n4T0wg==" + }, + "node_modules/@types/qs": { + "version": "6.9.8", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.8.tgz", + "integrity": "sha512-u95svzDlTysU5xecFNTgfFG5RUWu1A9P0VzgpcIiGZA9iraHOdSzcxMxQ55DyeRaGCSxQi7LxXDI4rzq/MYfdg==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.5.tgz", + "integrity": "sha512-xrO9OoVPqFuYyR/loIHjnbvvyRZREYKLjxV4+dY6v3FQR3stQ9ZxIGkaclF7YhI9hfjpuTbu14hZEy94qKLtOA==", + "dev": true + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.2.tgz", + "integrity": "sha512-aAG6yRf6r0wQ29bkS+x97BIs64ZLxeE/ARwyS6wrldMm3C1MdKwCcnnEwMC1slI8wuxJOpiUH9MioC0A0i+GJw==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.2.tgz", + "integrity": "sha512-asaEIoc6J+DbBKXtO7p2shWUpKacZOoMBEGBgPG91P8xhO53ohzHWGCs4ScZo5pQMf5ukQzVT9fhX1WzpHihig==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.3.tgz", + "integrity": "sha512-yVRvFsEMrv7s0lGhzrggJjNOSmZCdgCjw9xWrPr/kNNLp6FaDfMC1KaYl3TSJ0c58bECwNBMoQrZJ8hA8E1eFg==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.34", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.34.tgz", + "integrity": "sha512-R+n7qBFnm/6jinlteC9DBL5dGiDGjWAvjo4viUanpnc/dG1y7uDoacXPIQ/PQEg1fI912SMHIa014ZjRpvDw4g==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ws": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.6.tgz", + "integrity": "sha512-8B5EO9jLVCy+B58PLHvLDuOD8DRVMgQzq8d55SjLCOn9kqGyqOvy27exVaTio1q1nX5zLu8/6N0n2ThSxOM6tg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + }, + "node_modules/babel-loader": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.2.1.tgz", + "integrity": "sha512-fqe8naHt46e0yIdkjUZYqddSXfej3AHajX+CSO5X7oy0EmPc6o5Xh+RClNoHjnieWz9AW4kZxW9yyFMhVB1QLA==", + "dev": true, + "dependencies": { + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0", + "webpack": ">=5" + } + }, + "node_modules/babel-loader/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/babel-loader/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/babel-loader/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/babel-loader/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", + "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.2", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", + "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.2", + "core-js-compat": "^3.38.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", + "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base-x": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.0.tgz", + "integrity": "sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==" + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/blakejs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==" + }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/bonjour-service": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.1.tgz", + "integrity": "sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg==", + "dev": true, + "dependencies": { + "array-flatten": "^2.1.2", + "dns-equal": "^1.0.0", + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", + "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001646", + "electron-to-chromium": "^1.5.4", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs58": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz", + "integrity": "sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==", + "dependencies": { + "base-x": "^4.0.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/byteify": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/byteify/-/byteify-4.1.4.tgz", + "integrity": "sha512-txz7sDGm+pJAMMyum7P5lQscyn7GSkJJtHyoUkMkUj4mUwpDz9oARWy4QrKUXYvfx4jV0DUyIFXm/qINNWd/Qg==", + "engines": { + "node": ">=14.16" + } + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cachedir": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.4.0.tgz", + "integrity": "sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001663", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001663.tgz", + "integrity": "sha512-o9C3X27GLKbLeTYZ6HBOLU1tsAcBZsLis28wrVzddShCS16RujjHp9GDHKZqrB3meE0YjhawvMFsGb/igqiPzA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", + "dev": true + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "dev": true, + "dependencies": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/copy-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/copy-webpack-plugin/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/copy-webpack-plugin/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/core-js-compat": { + "version": "3.38.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.38.1.tgz", + "integrity": "sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==", + "dev": true, + "dependencies": { + "browserslist": "^4.23.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-loader": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.8.1.tgz", + "integrity": "sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g==", + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.21", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.3", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.8" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==", + "dev": true + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dev": true, + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.27", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.27.tgz", + "integrity": "sha512-o37j1vZqCoEgBuWWXLHQgTN/KDKe7zwpiY5CPeq2RvUqOyJw9xnrULzZAEVQ5p4h+zjMk7hgtOoPdnLxr7m/jw==" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/envinfo": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.10.0.tgz", + "integrity": "sha512-ZtUjZO6l5mwTHvc1L9+1q5p/R3wTopcfqMW8r5t8SJSKqeVI/LtajORwRFEKpEFuekjD0VBjwu1HMxL4UalIRw==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.1.tgz", + "integrity": "sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q==" + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/express": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", + "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.10", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-cache-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", + "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", + "dev": true, + "dependencies": { + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "dev": true, + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dev": true, + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dev": true, + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/find-cache-dir/node_modules/pkg-dir": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", + "dev": true, + "dependencies": { + "find-up": "^6.3.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz", + "integrity": "sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", + "dev": true, + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-entities": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz", + "integrity": "sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dev": true, + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ignore": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/ipaddr.js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", + "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", + "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isomorphic-fetch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz", + "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==", + "dependencies": { + "node-fetch": "^2.6.1", + "whatwg-fetch": "^3.4.1" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/js-sha256": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz", + "integrity": "sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/launch-editor": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.0.tgz", + "integrity": "sha512-JpDCcQnyAAzZZaZ7vEiSqL690w7dAEyLao+KC96zBplnYbJS7TYNjvM3M7y3dGz+v7aIsJk3hllWuc0kWAjyRQ==", + "dev": true, + "dependencies": { + "picocolors": "^1.0.0", + "shell-quote": "^1.7.3" + } + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/nanoid": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/o1js": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/o1js/-/o1js-1.8.0.tgz", + "integrity": "sha512-mN0aM4HW3kyl/Gx0irqKQSQ2JftbmsK2t5nSZpTuNgTOVl0wQ6KZumXXps6E5hGkCjRfk+FjlL7CBsmqKqzYzg==", + "dependencies": { + "blakejs": "1.2.1", + "cachedir": "^2.4.0", + "isomorphic-fetch": "^3.0.0", + "js-sha256": "^0.9.0", + "reflect-metadata": "^0.1.13", + "tslib": "^2.3.0" + }, + "bin": { + "snarky-run": "src/build/run.js" + }, + "engines": { + "node": ">=18.14.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-to-regexp": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz", + "integrity": "sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==", + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", + "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-loader": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-0.5.1.tgz", + "integrity": "sha512-sf7oGoLuaYAScB4VGr0tzetsYlS8EJH6qnTCfQ/WVEa89hALQ4RQfCKt5xCyPQKPDUbVUAIP1QsxAwfAjlDp7Q==" + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dev": true, + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.6", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz", + "integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/script-loader": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/script-loader/-/script-loader-0.7.2.tgz", + "integrity": "sha512-UMNLEvgOAQuzK8ji8qIscM3GIrRCWN6MmMXGD4SD5l6cSycgGsCo0tX5xRnfQcoghqct0tjHjcykgI1PyBE2aA==", + "dependencies": { + "raw-loader": "~0.5.1" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, + "node_modules/selfsigned": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz", + "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==", + "dev": true, + "dependencies": { + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/spdy-transport/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/spdy-transport/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/spdy/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/spdy/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/style-loader": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.3.tgz", + "integrity": "sha512-53BiGLXAcll9maCYtZi2RCQZKa8NQQai5C4horqKyRmHj9H7QmcUyucrH+4KW/gBQbXM2AsB0axoEcFZPlfPcw==", + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.33.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.33.0.tgz", + "integrity": "sha512-JuPVaB7s1gdFKPKTelwUyRq5Sid2A3Gko2S0PncwdBq7kN9Ti9HPWDQ06MPsEDGsZeVESjKEnyGy68quBk1w6g==", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/ts-loader": { + "version": "9.4.4", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.4.tgz", + "integrity": "sha512-MLukxDHBl8OJ5Dk3y69IsKVFRA/6MwzEqBgh+OXMPB/OD01KQuWPFd1WAQP8a5PeSCAxfnkhiuWqfmFJzJQt9w==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" + } + }, + "node_modules/ts-loader/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ts-loader/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ts-loader/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/ts-loader/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/ts-loader/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/watchpack": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/webpack": { + "version": "5.94.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz", + "integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==", + "dependencies": { + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", + "acorn": "^8.7.1", + "acorn-import-attributes": "^1.9.5", + "browserslist": "^4.21.10", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.1", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", + "colorette": "^2.0.14", + "commander": "^10.0.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/webpack-dev-middleware": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", + "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/webpack-dev-middleware/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server": { + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", + "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", + "dev": true, + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.5", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.13.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-server/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-merge": { + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.9.0.tgz", + "integrity": "sha512-6NbRQw4+Sy50vYNTw7EyOn41OZItPiXB8GNv3INSoe3PSFaHJEz3SHTrYVaRm2LilNGnFUzh0FAwqPEmU/CwDg==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/whatwg-fetch": { + "version": "3.6.19", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.19.tgz", + "integrity": "sha512-d67JP4dHSbm2TrpFj8AbO8DnL1JXL5J9u0Kq2xW6d0TFDbCA3Muhdt8orXC22utleTVj7Prqt82baN6RBvnEgw==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/ws": { + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@babel/code-frame": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "dev": true, + "requires": { + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + } + }, + "@babel/compat-data": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.4.tgz", + "integrity": "sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==", + "dev": true + }, + "@babel/core": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.6.tgz", + "integrity": "sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==", + "dev": true, + "requires": { + "@babel/types": "^7.25.6", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", + "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", + "dev": true, + "requires": { + "@babel/types": "^7.24.7" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz", + "integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==", + "dev": true, + "requires": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", + "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.25.2", + "@babel/helper-validator-option": "^7.24.8", + "browserslist": "^4.23.1", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.4.tgz", + "integrity": "sha512-ro/bFs3/84MDgDmMwbcHgDa8/E6J3QKNTk4xJJnVeFtGE+tL0K26E3pNxhYz2b67fJpt7Aphw5XcploKXuCvCQ==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-member-expression-to-functions": "^7.24.8", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/helper-replace-supers": "^7.25.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/traverse": "^7.25.4", + "semver": "^6.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.2.tgz", + "integrity": "sha512-+wqVGP+DFmqwFD3EH6TMTfUNeqDehV3E/dl+Sd54eaXqm17tEUNbEIn4sVivVowbvUpOtIGxdo3GoXyDH9N/9g==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "@babel/helper-define-polyfill-provider": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", + "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "dependencies": { + "debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "requires": { + "ms": "^2.1.3" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + } + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", + "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==", + "dev": true, + "requires": { + "@babel/traverse": "^7.24.8", + "@babel/types": "^7.24.8" + } + }, + "@babel/helper-module-imports": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "dev": true, + "requires": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + } + }, + "@babel/helper-module-transforms": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", + "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.2" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", + "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", + "dev": true, + "requires": { + "@babel/types": "^7.24.7" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", + "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", + "dev": true + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.0.tgz", + "integrity": "sha512-NhavI2eWEIz/H9dbrG0TuOicDhNexze43i5z7lEqwYm0WEZVTwnPpA0EafUTP7+6/W79HWIP2cTe3Z5NiSTVpw==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-wrap-function": "^7.25.0", + "@babel/traverse": "^7.25.0" + } + }, + "@babel/helper-replace-supers": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.0.tgz", + "integrity": "sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.24.8", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/traverse": "^7.25.0" + } + }, + "@babel/helper-simple-access": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "dev": true, + "requires": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", + "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", + "dev": true, + "requires": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + } + }, + "@babel/helper-string-parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "dev": true + }, + "@babel/helper-validator-identifier": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", + "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", + "dev": true + }, + "@babel/helper-wrap-function": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.0.tgz", + "integrity": "sha512-s6Q1ebqutSiZnEjaofc/UKDyC4SbzV5n5SrA2Gq8UawLycr3i04f1dX4OzoQVnexm6aOCh37SQNYlJ/8Ku+PMQ==", + "dev": true, + "requires": { + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.0", + "@babel/types": "^7.25.0" + } + }, + "@babel/helpers": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.6.tgz", + "integrity": "sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==", + "dev": true, + "requires": { + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.6" + } + }, + "@babel/highlight": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + } + }, + "@babel/parser": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.6.tgz", + "integrity": "sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==", + "dev": true, + "requires": { + "@babel/types": "^7.25.6" + } + }, + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.3.tgz", + "integrity": "sha512-wUrcsxZg6rqBXG05HG1FPYgsP6EvwF4WpBbxIpWIIYnH8wG0gzx3yZY3dtEHas4sTAOGkbTsc9EGPxwff8lRoA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.3" + } + }, + "@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.0.tgz", + "integrity": "sha512-Bm4bH2qsX880b/3ziJ8KD711LT7z4u8CFudmjqle65AZj/HNUFhEf90dqYv6O86buWvSBmeQDjv0Tn2aF/bIBA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.8" + } + }, + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.0.tgz", + "integrity": "sha512-lXwdNZtTmeVOOFtwM/WDe7yg1PL8sYhRk/XH0FzbR2HDQ0xC+EnQ/JHeoMYSavtU115tnUk0q9CDyq8si+LMAA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.8" + } + }, + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz", + "integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.7" + } + }, + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.0.tgz", + "integrity": "sha512-tggFrk1AIShG/RUQbEwt2Tr/E+ObkfwrPjR6BjbRvsx24+PSjK8zrq0GWPNCjo8qpRx4DuJzlcvWJqlm+0h3kw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.0" + } + }, + "@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "requires": {} + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-syntax-import-assertions": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.25.6.tgz", + "integrity": "sha512-aABl0jHw9bZ2karQ/uUD6XP4u0SG22SJrOHFoL6XB1R7dTovOP4TzTlsxOYC5yQ1pdscVK2JTUnF6QL3ARoAiQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.8" + } + }, + "@babel/plugin-syntax-import-attributes": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.6.tgz", + "integrity": "sha512-sXaDXaJN9SNLymBdlWFA+bjzBhFD617ZaFiY13dGt7TVslVvVgA6fkZOP7Ki3IGElC45lwHdOTrCtKZGVAWeLQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.8" + } + }, + "@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz", + "integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7" + } + }, + "@babel/plugin-transform-async-generator-functions": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.4.tgz", + "integrity": "sha512-jz8cV2XDDTqjKPwVPJBIjORVEmSGYhdRa8e5k5+vN+uwcjSrSxUaebBRa4ko1jqNF2uxyg8G6XYk30Jv285xzg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-remap-async-to-generator": "^7.25.0", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/traverse": "^7.25.4" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz", + "integrity": "sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-remap-async-to-generator": "^7.24.7" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz", + "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.0.tgz", + "integrity": "sha512-yBQjYoOjXlFv9nlXb3f1casSHOZkWr29NX+zChVanLg5Nc157CrbEX9D7hxxtTpuFy7Q0YzmmWfJxzvps4kXrQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.8" + } + }, + "@babel/plugin-transform-class-properties": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.4.tgz", + "integrity": "sha512-nZeZHyCWPfjkdU5pA/uHiTaDAFUEqkpzf1YoQT2NeSynCGYq9rxfyI3XpQbfx/a0hSnFH6TGlEXvae5Vi7GD8g==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.25.4", + "@babel/helper-plugin-utils": "^7.24.8" + } + }, + "@babel/plugin-transform-class-static-block": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz", + "integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.4.tgz", + "integrity": "sha512-oexUfaQle2pF/b6E0dwsxQtAol9TLSO88kQvym6HHBWFliV2lGdrPieX+WgMRLSJDVzdYywk7jXbLPuO2KLTLg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-replace-supers": "^7.25.0", + "@babel/traverse": "^7.25.4", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", + "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/template": "^7.24.7" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.8.tgz", + "integrity": "sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.8" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz", + "integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz", + "integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7" + } + }, + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.0.tgz", + "integrity": "sha512-YLpb4LlYSc3sCUa35un84poXoraOiQucUTTu8X1j18JV+gNa8E0nyUf/CjZ171IRGr4jEguF+vzJU66QZhn29g==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8" + } + }, + "@babel/plugin-transform-dynamic-import": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", + "integrity": "sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz", + "integrity": "sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + } + }, + "@babel/plugin-transform-export-namespace-from": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz", + "integrity": "sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz", + "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.25.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.1.tgz", + "integrity": "sha512-TVVJVdW9RKMNgJJlLtHsKDTydjZAbwIsn6ySBPQaEAUU5+gVvlJt/9nRmqVbsV/IBanRjzWoaAQKLoamWVOUuA==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.1" + } + }, + "@babel/plugin-transform-json-strings": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz", + "integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-json-strings": "^7.8.3" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.2.tgz", + "integrity": "sha512-HQI+HcTbm9ur3Z2DkO+jgESMAMcYLuN/A7NRw9juzxAezN9AvqvUTnpKP/9kkYANz6u7dFlAyOu44ejuGySlfw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.8" + } + }, + "@babel/plugin-transform-logical-assignment-operators": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz", + "integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz", + "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz", + "integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz", + "integrity": "sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-simple-access": "^7.24.7" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.0.tgz", + "integrity": "sha512-YPJfjQPDXxyQWg/0+jHKj1llnY5f/R6a0p/vP4lPymxLu7Lvl4k2WMitqi08yxwQcCVUUdG9LCUj4TNEgAp3Jw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.0" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz", + "integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz", + "integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz", + "integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7" + } + }, + "@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz", + "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + } + }, + "@babel/plugin-transform-numeric-separator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz", + "integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-transform-object-rest-spread": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz", + "integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.24.7" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz", + "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7" + } + }, + "@babel/plugin-transform-optional-catch-binding": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz", + "integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + } + }, + "@babel/plugin-transform-optional-chaining": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz", + "integrity": "sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz", + "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7" + } + }, + "@babel/plugin-transform-private-methods": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.4.tgz", + "integrity": "sha512-ao8BG7E2b/URaUQGqN3Tlsg+M3KlHY6rJ1O1gXAEUnZoyNQnvKyH87Kfg+FoxSeyWUB8ISZZsC91C44ZuBFytw==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.25.4", + "@babel/helper-plugin-utils": "^7.24.8" + } + }, + "@babel/plugin-transform-private-property-in-object": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz", + "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz", + "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz", + "integrity": "sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7", + "regenerator-transform": "^0.15.2" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz", + "integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7" + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz", + "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz", + "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz", + "integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", + "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz", + "integrity": "sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.8" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz", + "integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.7" + } + }, + "@babel/plugin-transform-unicode-property-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz", + "integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz", + "integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + } + }, + "@babel/plugin-transform-unicode-sets-regex": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.4.tgz", + "integrity": "sha512-qesBxiWkgN1Q+31xUE9RcMk79eOXXDCv6tfyGMRSs4RGlioSg2WVyQAm07k726cSE56pa+Kb0y9epX2qaXzTvA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8" + } + }, + "@babel/preset-env": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.4.tgz", + "integrity": "sha512-W9Gyo+KmcxjGahtt3t9fb14vFRWvPpu5pT6GBlovAK6BTBcxgjfVMSQCfJl4oi35ODrxP6xx2Wr8LNST57Mraw==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.25.4", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-validator-option": "^7.24.8", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.3", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.0", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.0", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.0", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.24.7", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.24.7", + "@babel/plugin-transform-async-generator-functions": "^7.25.4", + "@babel/plugin-transform-async-to-generator": "^7.24.7", + "@babel/plugin-transform-block-scoped-functions": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.25.0", + "@babel/plugin-transform-class-properties": "^7.25.4", + "@babel/plugin-transform-class-static-block": "^7.24.7", + "@babel/plugin-transform-classes": "^7.25.4", + "@babel/plugin-transform-computed-properties": "^7.24.7", + "@babel/plugin-transform-destructuring": "^7.24.8", + "@babel/plugin-transform-dotall-regex": "^7.24.7", + "@babel/plugin-transform-duplicate-keys": "^7.24.7", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.0", + "@babel/plugin-transform-dynamic-import": "^7.24.7", + "@babel/plugin-transform-exponentiation-operator": "^7.24.7", + "@babel/plugin-transform-export-namespace-from": "^7.24.7", + "@babel/plugin-transform-for-of": "^7.24.7", + "@babel/plugin-transform-function-name": "^7.25.1", + "@babel/plugin-transform-json-strings": "^7.24.7", + "@babel/plugin-transform-literals": "^7.25.2", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", + "@babel/plugin-transform-member-expression-literals": "^7.24.7", + "@babel/plugin-transform-modules-amd": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.8", + "@babel/plugin-transform-modules-systemjs": "^7.25.0", + "@babel/plugin-transform-modules-umd": "^7.24.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", + "@babel/plugin-transform-new-target": "^7.24.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", + "@babel/plugin-transform-numeric-separator": "^7.24.7", + "@babel/plugin-transform-object-rest-spread": "^7.24.7", + "@babel/plugin-transform-object-super": "^7.24.7", + "@babel/plugin-transform-optional-catch-binding": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.8", + "@babel/plugin-transform-parameters": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.25.4", + "@babel/plugin-transform-private-property-in-object": "^7.24.7", + "@babel/plugin-transform-property-literals": "^7.24.7", + "@babel/plugin-transform-regenerator": "^7.24.7", + "@babel/plugin-transform-reserved-words": "^7.24.7", + "@babel/plugin-transform-shorthand-properties": "^7.24.7", + "@babel/plugin-transform-spread": "^7.24.7", + "@babel/plugin-transform-sticky-regex": "^7.24.7", + "@babel/plugin-transform-template-literals": "^7.24.7", + "@babel/plugin-transform-typeof-symbol": "^7.24.8", + "@babel/plugin-transform-unicode-escapes": "^7.24.7", + "@babel/plugin-transform-unicode-property-regex": "^7.24.7", + "@babel/plugin-transform-unicode-regex": "^7.24.7", + "@babel/plugin-transform-unicode-sets-regex": "^7.25.4", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.6", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.37.1", + "semver": "^6.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + } + }, + "@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", + "dev": true + }, + "@babel/runtime": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.6.tgz", + "integrity": "sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.14.0" + } + }, + "@babel/template": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", + "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.25.0", + "@babel/types": "^7.25.0" + } + }, + "@babel/traverse": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.6.tgz", + "integrity": "sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.6", + "@babel/parser": "^7.25.6", + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.6", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.6.tgz", + "integrity": "sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "to-fast-properties": "^2.0.0" + } + }, + "@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true + }, + "@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "requires": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==" + }, + "@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==" + }, + "@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "requires": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", + "dev": true + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@types/body-parser": { + "version": "1.19.3", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.3.tgz", + "integrity": "sha512-oyl4jvAfTGX9Bt6Or4H9ni1Z447/tQuxnZsytsCaExKlmJiU8sFgnIBRzJUpKwB5eWn9HuBYlUlVA74q/yN0eQ==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/bonjour": { + "version": "3.5.11", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.11.tgz", + "integrity": "sha512-isGhjmBtLIxdHBDl2xGwUzEM8AOyOvWsADWq7rqirdi/ZQoHnLWErHvsThcEzTX8juDRiZtzp2Qkv5bgNh6mAg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.36", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.36.tgz", + "integrity": "sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/connect-history-api-fallback": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.1.tgz", + "integrity": "sha512-iaQslNbARe8fctL5Lk+DsmgWOM83lM+7FzP0eQUJs1jd3kBE8NWqBTIT2S8SqQOJjxvt2eyIjpOuYeRXq2AdMw==", + "dev": true, + "requires": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==" + }, + "@types/express": { + "version": "4.17.18", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.18.tgz", + "integrity": "sha512-Sxv8BSLLgsBYmcnGdGjjEjqET2U+AKAdCRODmMiq02FgjwuV75Ut85DRpvFjyw/Mk0vgUOliGRU0UUmuuZHByQ==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.37", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.37.tgz", + "integrity": "sha512-ZohaCYTgGFcOP7u6aJOhY9uIZQgZ2vxC2yWoArY+FeDXlqeH66ZVBjgvg+RLVAS/DWNq4Ap9ZXu1+SUQiiWYMg==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "@types/http-errors": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.2.tgz", + "integrity": "sha512-lPG6KlZs88gef6aD85z3HNkztpj7w2R7HmR3gygjfXCQmsLloWNARFkMuzKiiY8FGdh1XDpgBdrSf4aKDiA7Kg==", + "dev": true + }, + "@types/http-proxy": { + "version": "1.17.12", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.12.tgz", + "integrity": "sha512-kQtujO08dVtQ2wXAuSFfk9ASy3sug4+ogFR8Kd8UgP8PEuc1/G/8yjYRmp//PcDNJEUKOza/MrQu15bouEUCiw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/json-schema": { + "version": "7.0.13", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz", + "integrity": "sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==" + }, + "@types/mime": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.3.tgz", + "integrity": "sha512-Ys+/St+2VF4+xuY6+kDIXGxbNRO0mesVg0bbxEfB97Od1Vjpjx9KD1qxs64Gcb3CWPirk9Xe+PT4YiiHQ9T+eg==", + "dev": true + }, + "@types/node": { + "version": "20.7.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.7.1.tgz", + "integrity": "sha512-LT+OIXpp2kj4E2S/p91BMe+VgGX2+lfO+XTpfXhh+bCk2LkQtHZSub8ewFBMGP5ClysPjTDFa4sMI8Q3n4T0wg==" + }, + "@types/qs": { + "version": "6.9.8", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.8.tgz", + "integrity": "sha512-u95svzDlTysU5xecFNTgfFG5RUWu1A9P0VzgpcIiGZA9iraHOdSzcxMxQ55DyeRaGCSxQi7LxXDI4rzq/MYfdg==", + "dev": true + }, + "@types/range-parser": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.5.tgz", + "integrity": "sha512-xrO9OoVPqFuYyR/loIHjnbvvyRZREYKLjxV4+dY6v3FQR3stQ9ZxIGkaclF7YhI9hfjpuTbu14hZEy94qKLtOA==", + "dev": true + }, + "@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true + }, + "@types/send": { + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.2.tgz", + "integrity": "sha512-aAG6yRf6r0wQ29bkS+x97BIs64ZLxeE/ARwyS6wrldMm3C1MdKwCcnnEwMC1slI8wuxJOpiUH9MioC0A0i+GJw==", + "dev": true, + "requires": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "@types/serve-index": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.2.tgz", + "integrity": "sha512-asaEIoc6J+DbBKXtO7p2shWUpKacZOoMBEGBgPG91P8xhO53ohzHWGCs4ScZo5pQMf5ukQzVT9fhX1WzpHihig==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, + "@types/serve-static": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.3.tgz", + "integrity": "sha512-yVRvFsEMrv7s0lGhzrggJjNOSmZCdgCjw9xWrPr/kNNLp6FaDfMC1KaYl3TSJ0c58bECwNBMoQrZJ8hA8E1eFg==", + "dev": true, + "requires": { + "@types/http-errors": "*", + "@types/mime": "*", + "@types/node": "*" + } + }, + "@types/sockjs": { + "version": "0.3.34", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.34.tgz", + "integrity": "sha512-R+n7qBFnm/6jinlteC9DBL5dGiDGjWAvjo4viUanpnc/dG1y7uDoacXPIQ/PQEg1fI912SMHIa014ZjRpvDw4g==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/ws": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.6.tgz", + "integrity": "sha512-8B5EO9jLVCy+B58PLHvLDuOD8DRVMgQzq8d55SjLCOn9kqGyqOvy27exVaTio1q1nX5zLu8/6N0n2ThSxOM6tg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@webassemblyjs/ast": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "requires": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==" + }, + "@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==" + }, + "@webassemblyjs/helper-buffer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==" + }, + "@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "requires": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==" + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "requires": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==" + }, + "@webassemblyjs/wasm-edit": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "requires": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "requires": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "requires": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "requires": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "requires": { + "@webassemblyjs/ast": "1.12.1", + "@xtuc/long": "4.2.2" + } + }, + "@webpack-cli/configtest": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "dev": true, + "requires": {} + }, + "@webpack-cli/info": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "dev": true, + "requires": {} + }, + "@webpack-cli/serve": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "dev": true, + "requires": {} + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==" + }, + "acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "requires": {} + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "requires": { + "ajv": "^8.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "requires": {} + }, + "ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + }, + "babel-loader": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.2.1.tgz", + "integrity": "sha512-fqe8naHt46e0yIdkjUZYqddSXfej3AHajX+CSO5X7oy0EmPc6o5Xh+RClNoHjnieWz9AW4kZxW9yyFMhVB1QLA==", + "dev": true, + "requires": { + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + } + } + } + }, + "babel-plugin-polyfill-corejs2": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", + "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.2", + "semver": "^6.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "babel-plugin-polyfill-corejs3": { + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", + "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.6.2", + "core-js-compat": "^3.38.0" + } + }, + "babel-plugin-polyfill-regenerator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", + "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.6.2" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "base-x": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.0.tgz", + "integrity": "sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==" + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "blakejs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==" + }, + "body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + } + } + }, + "bonjour-service": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.1.tgz", + "integrity": "sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg==", + "dev": true, + "requires": { + "array-flatten": "^2.1.2", + "dns-equal": "^1.0.0", + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browserslist": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", + "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", + "requires": { + "caniuse-lite": "^1.0.30001646", + "electron-to-chromium": "^1.5.4", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" + } + }, + "bs58": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz", + "integrity": "sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==", + "requires": { + "base-x": "^4.0.0" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "byteify": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/byteify/-/byteify-4.1.4.tgz", + "integrity": "sha512-txz7sDGm+pJAMMyum7P5lQscyn7GSkJJtHyoUkMkUj4mUwpDz9oARWy4QrKUXYvfx4jV0DUyIFXm/qINNWd/Qg==" + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true + }, + "cachedir": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.4.0.tgz", + "integrity": "sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ==" + }, + "call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + } + }, + "caniuse-lite": { + "version": "1.0.30001663", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001663.tgz", + "integrity": "sha512-o9C3X27GLKbLeTYZ6HBOLU1tsAcBZsLis28wrVzddShCS16RujjHp9GDHKZqrB3meE0YjhawvMFsGb/igqiPzA==" + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==" + }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", + "dev": true + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "requires": { + "safe-buffer": "5.2.1" + } + }, + "content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" + }, + "convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "dev": true, + "requires": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + } + } + } + }, + "core-js-compat": { + "version": "3.38.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.38.1.tgz", + "integrity": "sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==", + "dev": true, + "requires": { + "browserslist": "^4.23.3" + } + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "css-loader": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.8.1.tgz", + "integrity": "sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g==", + "requires": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.21", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.3", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.8" + } + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "requires": { + "execa": "^5.0.0" + } + }, + "define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + } + }, + "define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" + }, + "detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==", + "dev": true + }, + "dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dev": true, + "requires": { + "@leichtgewicht/ip-codec": "^2.0.1" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "electron-to-chromium": { + "version": "1.5.27", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.27.tgz", + "integrity": "sha512-o37j1vZqCoEgBuWWXLHQgTN/KDKe7zwpiY5CPeq2RvUqOyJw9xnrULzZAEVQ5p4h+zjMk7hgtOoPdnLxr7m/jw==" + }, + "encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" + }, + "enhanced-resolve": { + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, + "envinfo": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.10.0.tgz", + "integrity": "sha512-ZtUjZO6l5mwTHvc1L9+1q5p/R3wTopcfqMW8r5t8SJSKqeVI/LtajORwRFEKpEFuekjD0VBjwu1HMxL4UalIRw==", + "dev": true + }, + "es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "requires": { + "get-intrinsic": "^1.2.4" + } + }, + "es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" + }, + "es-module-lexer": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.1.tgz", + "integrity": "sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q==" + }, + "escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" + }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "express": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", + "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.10", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + } + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true + }, + "fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + } + }, + "find-cache-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", + "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", + "dev": true, + "requires": { + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" + }, + "dependencies": { + "find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "dev": true, + "requires": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + } + }, + "locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dev": true, + "requires": { + "p-locate": "^6.0.0" + } + }, + "p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "requires": { + "yocto-queue": "^1.0.0" + } + }, + "p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dev": true, + "requires": { + "p-limit": "^4.0.0" + } + }, + "path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "dev": true + }, + "pkg-dir": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", + "dev": true, + "requires": { + "find-up": "^6.3.0" + } + } + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "dev": true + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + }, + "fs-monkey": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz", + "integrity": "sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "globby": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", + "dev": true, + "requires": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", + "merge2": "^1.4.1", + "slash": "^4.0.0" + } + }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "requires": { + "es-define-property": "^1.0.0" + } + }, + "has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==" + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "requires": { + "function-bind": "^1.1.2" + } + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "html-entities": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz", + "integrity": "sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ==", + "dev": true + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true + }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dev": true, + "requires": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + } + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "requires": {} + }, + "ignore": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "dev": true + }, + "import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true + }, + "ipaddr.js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", + "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-core-module": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", + "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "requires": { + "is-docker": "^2.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true + }, + "isomorphic-fetch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz", + "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==", + "requires": { + "node-fetch": "^2.6.1", + "whatwg-fetch": "^3.4.1" + } + }, + "jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + } + }, + "js-sha256": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz", + "integrity": "sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==" + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "launch-editor": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.0.tgz", + "integrity": "sha512-JpDCcQnyAAzZZaZ7vEiSqL690w7dAEyLao+KC96zBplnYbJS7TYNjvM3M7y3dGz+v7aIsJk3hllWuc0kWAjyRQ==", + "dev": true, + "requires": { + "picocolors": "^1.0.0", + "shell-quote": "^1.7.3" + } + }, + "loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==" + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" + }, + "memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "requires": { + "fs-monkey": "^1.0.4" + } + }, + "merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==" + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "requires": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + } + }, + "nanoid": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==" + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true + }, + "node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==" + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "o1js": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/o1js/-/o1js-1.8.0.tgz", + "integrity": "sha512-mN0aM4HW3kyl/Gx0irqKQSQ2JftbmsK2t5nSZpTuNgTOVl0wQ6KZumXXps6E5hGkCjRfk+FjlL7CBsmqKqzYzg==", + "requires": { + "blakejs": "1.2.1", + "cachedir": "^2.4.0", + "isomorphic-fetch": "^3.0.0", + "js-sha256": "^0.9.0", + "reflect-metadata": "^0.1.13", + "tslib": "^2.3.0" + } + }, + "object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==" + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "requires": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "requires": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "picocolors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==" + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "requires": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "requires": {} + }, + "postcss-modules-local-by-default": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz", + "integrity": "sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==", + "requires": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + } + }, + "postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "requires": { + "postcss-selector-parser": "^6.0.4" + } + }, + "postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "requires": { + "icss-utils": "^5.0.0" + } + }, + "postcss-selector-parser": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", + "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "dependencies": { + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + } + } + }, + "punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==" + }, + "qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "requires": { + "side-channel": "^1.0.6" + } + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + } + } + }, + "raw-loader": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-0.5.1.tgz", + "integrity": "sha512-sf7oGoLuaYAScB4VGr0tzetsYlS8EJH6qnTCfQ/WVEa89hALQ4RQfCKt5xCyPQKPDUbVUAIP1QsxAwfAjlDp7Q==" + }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "requires": { + "resolve": "^1.20.0" + } + }, + "reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" + }, + "regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "dev": true, + "requires": { + "regenerate": "^1.4.2" + } + }, + "regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true + }, + "regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.8.4" + } + }, + "regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dev": true, + "requires": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + } + }, + "regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true + } + } + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "resolve": { + "version": "1.22.6", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz", + "integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==", + "dev": true, + "requires": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + }, + "script-loader": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/script-loader/-/script-loader-0.7.2.tgz", + "integrity": "sha512-UMNLEvgOAQuzK8ji8qIscM3GIrRCWN6MmMXGD4SD5l6cSycgGsCo0tX5xRnfQcoghqct0tjHjcykgI1PyBE2aA==", + "requires": { + "raw-loader": "~0.5.1" + } + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, + "selfsigned": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz", + "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==", + "dev": true, + "requires": { + "node-forge": "^1" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "dependencies": { + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true + } + } + }, + "serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "requires": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + } + }, + "set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "requires": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + } + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "dev": true + }, + "side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "requires": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + } + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true + }, + "sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "requires": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, + "style-loader": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.3.tgz", + "integrity": "sha512-53BiGLXAcll9maCYtZi2RCQZKa8NQQai5C4horqKyRmHj9H7QmcUyucrH+4KW/gBQbXM2AsB0axoEcFZPlfPcw==", + "requires": {} + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==" + }, + "terser": { + "version": "5.33.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.33.0.tgz", + "integrity": "sha512-JuPVaB7s1gdFKPKTelwUyRq5Sid2A3Gko2S0PncwdBq7kN9Ti9HPWDQ06MPsEDGsZeVESjKEnyGy68quBk1w6g==", + "requires": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + } + }, + "terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "requires": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + } + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "ts-loader": { + "version": "9.4.4", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.4.tgz", + "integrity": "sha512-MLukxDHBl8OJ5Dk3y69IsKVFRA/6MwzEqBgh+OXMPB/OD01KQuWPFd1WAQP8a5PeSCAxfnkhiuWqfmFJzJQt9w==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "dev": true + }, + "unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" + }, + "update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "requires": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "requires": { + "punycode": "^2.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" + }, + "watchpack": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "webpack": { + "version": "5.94.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz", + "integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==", + "requires": { + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", + "acorn": "^8.7.1", + "acorn-import-attributes": "^1.9.5", + "browserslist": "^4.21.10", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.1", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + } + }, + "webpack-cli": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", + "dev": true, + "requires": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", + "colorette": "^2.0.14", + "commander": "^10.0.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "dependencies": { + "commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true + } + } + }, + "webpack-dev-middleware": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", + "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "dev": true, + "requires": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + } + } + } + }, + "webpack-dev-server": { + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", + "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", + "dev": true, + "requires": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.5", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.13.0" + }, + "dependencies": { + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + } + } + } + }, + "webpack-merge": { + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.9.0.tgz", + "integrity": "sha512-6NbRQw4+Sy50vYNTw7EyOn41OZItPiXB8GNv3INSoe3PSFaHJEz3SHTrYVaRm2LilNGnFUzh0FAwqPEmU/CwDg==", + "dev": true, + "requires": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + } + }, + "webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==" + }, + "websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "requires": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true + }, + "whatwg-fetch": { + "version": "3.6.19", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.19.tgz", + "integrity": "sha512-d67JP4dHSbm2TrpFj8AbO8DnL1JXL5J9u0Kq2xW6d0TFDbCA3Muhdt8orXC22utleTVj7Prqt82baN6RBvnEgw==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "ws": { + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", + "dev": true, + "requires": {} + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "dev": true + } + } +} diff --git a/frontend/src/assets/o1js/package.json b/frontend/src/assets/o1js/package.json new file mode 100644 index 0000000000..7a5d560b7e --- /dev/null +++ b/frontend/src/assets/o1js/package.json @@ -0,0 +1,32 @@ +{ + "name": "o1js-wrapper", + "version": "1.0.0", + "description": "This project is a JavaScript wrapper for interacting with O1JS in order to avoid integration issues between O1JS and Angular.", + "main": "dist/o1js-wrapper.js", + "scripts": { + "build-o1jswrapper": "webpack && node replace-assertion.js", + "serve": "webpack-dev-server --mode development" + }, + "author": "Jolte Teofil", + "license": "MIT", + "dependencies": { + "bs58": "^5.0.0", + "byteify": "^4.1.4", + "css-loader": "^6.8.1", + "express": "^4.21.0", + "o1js": "1.8.0", + "script-loader": "^0.7.2", + "style-loader": "^3.3.3" + }, + "devDependencies": { + "@babel/core": "^7.25.2", + "@babel/preset-env": "^7.25.4", + "babel-loader": "^9.2.1", + "copy-webpack-plugin": "^11.0.0", + "ts-loader": "^9.4.4", + "typescript": "^5.2.2", + "webpack": "^5.94.0", + "webpack-cli": "^5.1.4", + "webpack-dev-server": "^4.15.1" + } +} diff --git a/frontend/replace-assertion.js b/frontend/src/assets/o1js/replace-assertion.js similarity index 72% rename from frontend/replace-assertion.js rename to frontend/src/assets/o1js/replace-assertion.js index 2d7f16c74b..f63f55fa5b 100644 --- a/frontend/replace-assertion.js +++ b/frontend/src/assets/o1js/replace-assertion.js @@ -1,7 +1,7 @@ const fs = require('fs'); const path = require('path'); -const filePath = path.join(__dirname, 'src', 'assets', 'o1js', 'o1jsWrapper.js'); +const filePath = path.join(__dirname, 'dist', 'o1js-wrapper.js'); fs.readFile(filePath, 'utf8', (err, data) => { if (err) { @@ -9,7 +9,6 @@ fs.readFile(filePath, 'utf8', (err, data) => { process.exit(1); } - console.log('Replacement already done.'); const updatedContent = data.replace( /if\(!g\)throw Error/g, 'if(!g)new Error' @@ -17,7 +16,7 @@ fs.readFile(filePath, 'utf8', (err, data) => { fs.writeFile(filePath, updatedContent, 'utf8', (err) => { if (err) { - console.error('Error writing file:', err); + console.error('Error replacing content in file:', err); process.exit(1); } console.log('Replacement completed successfully.'); diff --git a/frontend/src/assets/o1js/src/index.ts b/frontend/src/assets/o1js/src/index.ts new file mode 100644 index 0000000000..c8eeb74d47 --- /dev/null +++ b/frontend/src/assets/o1js/src/index.ts @@ -0,0 +1,6 @@ +import { deployZkApp, updateZkApp } from './zk-app/zk-app'; + +export { + deployZkApp, + updateZkApp, +}; diff --git a/frontend/src/assets/o1js/src/zk-app/zk-app.ts b/frontend/src/assets/o1js/src/zk-app/zk-app.ts new file mode 100644 index 0000000000..a74f613e38 --- /dev/null +++ b/frontend/src/assets/o1js/src/zk-app/zk-app.ts @@ -0,0 +1,189 @@ +import { + AccountUpdate, + Field, + method, + Mina, + Permissions, + PrivateKey, + PublicKey, + SmartContract, + state, + State, +} from 'o1js'; + +class Add extends SmartContract { + @state(Field) num = State(); + + override init(): void { + this.account.provedState.requireEquals(this.account.provedState.get()); + this.account.provedState.get().assertFalse(); + + super.init(); + this.num.set(Field(1)); + } + + @method + async update() { + const currentState = this.num.getAndRequireEquals(); + const newState = currentState.add(5); + this.num.set(newState); + } + + override async deploy() { + super.deploy(); + this.account.permissions.set({ + ...Permissions.default(), + setDelegate: Permissions.signature(), + setPermissions: Permissions.signature(), + setZkappUri: Permissions.signature(), + setTokenSymbol: Permissions.signature(), + incrementNonce: Permissions.signature(), + setVotingFor: Permissions.signature(), + setTiming: Permissions.signature(), + send: Permissions.proof(), + editState: Permissions.proof(), + receive: Permissions.none(), + access: Permissions.none(), + editActionState: Permissions.proof(), + }); + } +} + +export interface ZkInput { + payerPublicKey: string; + payerPrivateKey: string; + fee: number; + nonce: string; + memo?: string; + accountUpdates: number; +} + +export async function deployZkApp(graphQlUrl: string, input: ZkInput, updates: { + next: (val: { step: string, duration: number }) => void +}): Promise { + console.log('----------- Sending ZkApp -----------'); + const network = Mina.Network(graphQlUrl); + Mina.setActiveInstance(network); + const pairs = Array.from({ length: input.accountUpdates }, () => { + const randPrivateKey = PrivateKey.random(); + return { + publicKey: randPrivateKey.toPublicKey(), + privateKey: randPrivateKey, + }; + }); + console.log(pairs.map((pair) => pair.privateKey.toBase58())); + const zkApps: Add[] = pairs.map((pair) => new Add(pair.publicKey)); + + let stepStartTime = performance.now(); + + const updateStep = (step: string) => { + const now = performance.now(); + if (step === 'Compiling') { + updates.next({ step, duration: undefined }); + return; + } + let duration = Math.round((now - stepStartTime) / 1000 * 1000) / 1000; + updates.next({ step, duration }); + console.log(`${step} (${duration}s)`); + stepStartTime = now; + }; + + updateStep('Compiling'); + await Add.compile(); + updateStep('Compiled'); + + const payerAccount = { + sender: PublicKey.fromBase58(input.payerPublicKey), + fee: input.fee * 1e9, + nonce: Number(input.nonce), + memo: input.memo, + }; + let tx = await Mina.transaction(payerAccount, async () => { + AccountUpdate.fundNewAccount(PublicKey.fromBase58(input.payerPublicKey), input.accountUpdates); + for (const zkApp of zkApps) { + await zkApp.deploy(); + } + }); + + updateStep('Deployed'); + + await tx.prove(); + updateStep('Proved'); + + await tx.sign([PrivateKey.fromBase58(input.payerPrivateKey), ...pairs.map((pair) => pair.privateKey)]); + updateStep('Signed'); + + return tx.safeSend().then((sentTx) => { + updateStep('Sent'); + console.log(sentTx); + console.log('----------- Done -----------'); + return sentTx; + }); +} + +const deployedZkApps: string[] = [ + 'EKEbTHeqQbq5zeFuspjVSoatEebrG7fJnz8CrXyP4aVAXzeD1Z6A', + 'EKFF1zZ4KUCZoe7GXHAPcfLdkGPgsYJ5RNtQvHMx8ndhY1pZttaa', +]; + +export async function updateZkApp(graphQlUrl: string, input: ZkInput, updates: { + next: (val: { step: string, duration: number }) => void +}): Promise { + console.log('----------- Updating ZkApp -----------'); + const network = Mina.Network(graphQlUrl); + Mina.setActiveInstance(network); + const pairs = Array.from({ length: input.accountUpdates }, (_, i: number) => { + const randPrivateKey = PrivateKey.fromBase58(deployedZkApps[i]); + return { + publicKey: randPrivateKey.toPublicKey(), + privateKey: randPrivateKey, + }; + }); + const zkApps: Add[] = pairs.map((pair) => new Add(pair.publicKey)); + + let stepStartTime = performance.now(); + + const updateStep = (step: string) => { + const now = performance.now(); + if (step === 'Compiling') { + updates.next({ step, duration: undefined }); + return; + } + let duration = Math.round((now - stepStartTime) / 1000 * 1000) / 1000; + updates.next({ step, duration }); + console.log(`${step} (${duration}s)`); + stepStartTime = now; + }; + updateStep('Compiling'); + + await Add.compile(); + updateStep('Compiled'); + + const payerAccount = { + sender: PublicKey.fromBase58(input.payerPublicKey), + fee: input.fee * 1e9, + nonce: Number(input.nonce), + memo: input.memo, + }; + let tx = await Mina.transaction(payerAccount, async () => { + for (const zkApp of zkApps) { + await zkApp.update(); + } + }); + + updateStep('Proved Check Even'); + + await tx.prove(); + updateStep('Proved'); + + await tx.sign([PrivateKey.fromBase58(input.payerPrivateKey), ...pairs.map((pair) => pair.privateKey)]); + updateStep('Signed'); + + return tx.safeSend().then((sentTx) => { + updateStep('Sent'); + updateStep(null); + console.log(sentTx); + console.log('----------- Done -----------'); + return sentTx; + }); +} diff --git a/frontend/src/assets/o1js/tsconfig.json b/frontend/src/assets/o1js/tsconfig.json new file mode 100644 index 0000000000..ad5ae642de --- /dev/null +++ b/frontend/src/assets/o1js/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "noImplicitAny": true, + "target": "ES2020", + "allowJs": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "useDefineForClassFields": false, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "skipLibCheck": true, + "module": "ES2020", + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true + } +} \ No newline at end of file diff --git a/frontend/src/assets/o1js/webpack.config.js b/frontend/src/assets/o1js/webpack.config.js new file mode 100644 index 0000000000..883bd28763 --- /dev/null +++ b/frontend/src/assets/o1js/webpack.config.js @@ -0,0 +1,46 @@ +const path = require('path'); + +module.exports = { + experiments: { + topLevelAwait: true, + }, + entry: path.resolve(__dirname, "bootstrap.js"), + output: { + path: path.resolve(__dirname, 'dist'), + umdNamedDefine: true, + publicPath: '/', + filename: "o1js-wrapper.js", + library: "o1jsWrapper", + libraryTarget: "umd", + globalObject: 'this', + }, + module: { + rules: [ + { + test: /\.ts?$/, + use: 'ts-loader', + exclude: /node_modules/, + }, + { + test: /\.(js)$/, + exclude: /node_modules/, + use: 'babel-loader', + }, + ], + }, + resolve: { + extensions: ['.tsx', '.ts', '.js'], + }, + mode: 'development', + devServer: { + static: { + directory: path.join(__dirname, 'dist'), + }, + compress: true, + port: 9000, + headers: { + 'Cross-Origin-Opener-Policy': 'same-origin', + 'Cross-Origin-Embedder-Policy': 'require-corp', + }, + }, +} diff --git a/frontend/src/assets/webnode/.gitignore b/frontend/src/assets/webnode/.gitignore new file mode 100644 index 0000000000..aa054e2d62 --- /dev/null +++ b/frontend/src/assets/webnode/.gitignore @@ -0,0 +1,3 @@ +#.gitignore +circuit-blobs +pkg diff --git a/frontend/src/assets/webnode/pkg/openmina_node_web.d.ts b/frontend/src/assets/webnode/pkg/openmina_node_web.d.ts deleted file mode 100644 index f214a967d8..0000000000 --- a/frontend/src/assets/webnode/pkg/openmina_node_web.d.ts +++ /dev/null @@ -1,115 +0,0 @@ -/* tslint:disable */ -/* eslint-disable */ -/** -* Automatically run after wasm is loaded. -*/ -export function main(): void; -/** -* @returns {Promise} -*/ -export function run(): Promise; -/** -* Entry point for web workers -* @param {number} ptr -*/ -export function wasm_thread_entry_point(ptr: number): void; -/** -*/ -export class RpcSender { - free(): void; -/** -* @returns {State} -*/ - state(): State; -/** -* @returns {Stats} -*/ - stats(): Stats; -/** -* @returns {Promise} -*/ - status(): Promise; -} -/** -*/ -export class State { - free(): void; -/** -* @returns {Promise} -*/ - peers(): Promise; -/** -* @returns {Promise} -*/ - message_progress(): Promise; -} -/** -*/ -export class Stats { - free(): void; -/** -* @param {number | undefined} [limit] -* @returns {Promise} -*/ - sync(limit?: number): Promise; -/** -* @returns {Promise} -*/ - block_producer(): Promise; -} - -export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module; - -export interface InitOutput { - readonly main: () => void; - readonly run: () => number; - readonly stats_sync: (a: number, b: number, c: number) => number; - readonly stats_block_producer: (a: number) => number; - readonly __wbg_state_free: (a: number, b: number) => void; - readonly state_peers: (a: number) => number; - readonly state_message_progress: (a: number) => number; - readonly __wbg_stats_free: (a: number, b: number) => void; - readonly __wbg_rpcsender_free: (a: number, b: number) => void; - readonly rpcsender_state: (a: number) => number; - readonly rpcsender_status: (a: number) => number; - readonly rpcsender_stats: (a: number) => number; - readonly wasm_thread_entry_point: (a: number) => void; - readonly memory: WebAssembly.Memory; - readonly __wbindgen_malloc: (a: number, b: number) => number; - readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number; - readonly __wbindgen_export_3: WebAssembly.Table; - readonly _dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hfc3cd25b53215e84: (a: number, b: number) => void; - readonly _dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h45df3e6947fcd651: (a: number, b: number, c: number) => void; - readonly _dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hd4a56f8647b4502b: (a: number, b: number) => void; - readonly _dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h92f8e55d458a8e39: (a: number, b: number) => void; - readonly _dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h90985823836ef819: (a: number, b: number, c: number) => void; - readonly _dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hff3e249b51682479: (a: number, b: number, c: number) => void; - readonly __wbindgen_free: (a: number, b: number, c: number) => void; - readonly __wbindgen_exn_store: (a: number) => void; - readonly wasm_bindgen__convert__closures__invoke2_mut__h808c9af25a9c04f4: (a: number, b: number, c: number, d: number) => void; - readonly __wbindgen_thread_destroy: (a?: number, b?: number, c?: number) => void; - readonly __wbindgen_start: (a: number) => void; -} - -export type SyncInitInput = BufferSource | WebAssembly.Module; -/** -* Instantiates the given `module`, which can either be bytes or -* a precompiled `WebAssembly.Module`. -* -* @param {{ module: SyncInitInput, memory?: WebAssembly.Memory, thread_stack_size?: number }} module - Passing `SyncInitInput` directly is deprecated. -* @param {WebAssembly.Memory} memory - Deprecated. -* -* @returns {InitOutput} -*/ -export function initSync(module: { module: SyncInitInput, memory?: WebAssembly.Memory, thread_stack_size?: number } | SyncInitInput, memory?: WebAssembly.Memory): InitOutput; - -/** -* If `module_or_path` is {RequestInfo} or {URL}, makes a request and -* for everything else, calls `WebAssembly.instantiate` directly. -* -* @param {{ module_or_path: InitInput | Promise, memory?: WebAssembly.Memory, thread_stack_size?: number }} module_or_path - Passing `InitInput` directly is deprecated. -* @param {WebAssembly.Memory} memory - Deprecated. -* -* @returns {Promise} -*/ -export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise, memory?: WebAssembly.Memory, thread_stack_size?: number } | InitInput | Promise, memory?: WebAssembly.Memory): Promise; diff --git a/frontend/src/assets/webnode/pkg/openmina_node_web.js b/frontend/src/assets/webnode/pkg/openmina_node_web.js deleted file mode 100644 index b4bc44213e..0000000000 --- a/frontend/src/assets/webnode/pkg/openmina_node_web.js +++ /dev/null @@ -1,1107 +0,0 @@ -import * as __wbg_star0 from './snippets/p2p-5e5eda2a182dce1e/src/service_impl/webrtc/web.js'; -import * as __wbg_star1 from './snippets/wasm_thread-8ee53d0673203880/src/wasm32/js/module_workers_polyfill.min.js'; - -let wasm; - -const heap = new Array(128).fill(undefined); - -heap.push(undefined, null, true, false); - -function getObject(idx) { return heap[idx]; } - -let heap_next = heap.length; - -function dropObject(idx) { - if (idx < 132) return; - heap[idx] = heap_next; - heap_next = idx; -} - -function takeObject(idx) { - const ret = getObject(idx); - dropObject(idx); - return ret; -} - -const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } ); - -if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); }; - -let cachedUint8ArrayMemory0 = null; - -function getUint8ArrayMemory0() { - if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.buffer !== wasm.memory.buffer) { - cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer); - } - return cachedUint8ArrayMemory0; -} - -function getStringFromWasm0(ptr, len) { - ptr = ptr >>> 0; - return cachedTextDecoder.decode(getUint8ArrayMemory0().slice(ptr, ptr + len)); -} - -function addHeapObject(obj) { - if (heap_next === heap.length) heap.push(heap.length + 1); - const idx = heap_next; - heap_next = heap[idx]; - - heap[idx] = obj; - return idx; -} - -function isLikeNone(x) { - return x === undefined || x === null; -} - -let cachedDataViewMemory0 = null; - -function getDataViewMemory0() { - if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer !== wasm.memory.buffer) { - cachedDataViewMemory0 = new DataView(wasm.memory.buffer); - } - return cachedDataViewMemory0; -} - -let WASM_VECTOR_LEN = 0; - -const cachedTextEncoder = (typeof TextEncoder !== 'undefined' ? new TextEncoder('utf-8') : { encode: () => { throw Error('TextEncoder not available') } } ); - -const encodeString = function (arg, view) { - const buf = cachedTextEncoder.encode(arg); - view.set(buf); - return { - read: arg.length, - written: buf.length - }; -}; - -function passStringToWasm0(arg, malloc, realloc) { - - if (realloc === undefined) { - const buf = cachedTextEncoder.encode(arg); - const ptr = malloc(buf.length, 1) >>> 0; - getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf); - WASM_VECTOR_LEN = buf.length; - return ptr; - } - - let len = arg.length; - let ptr = malloc(len, 1) >>> 0; - - const mem = getUint8ArrayMemory0(); - - let offset = 0; - - for (; offset < len; offset++) { - const code = arg.charCodeAt(offset); - if (code > 0x7F) break; - mem[ptr + offset] = code; - } - - if (offset !== len) { - if (offset !== 0) { - arg = arg.slice(offset); - } - ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0; - const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len); - const ret = encodeString(arg, view); - - offset += ret.written; - ptr = realloc(ptr, len, offset, 1) >>> 0; - } - - WASM_VECTOR_LEN = offset; - return ptr; -} - -function debugString(val) { - // primitive types - const type = typeof val; - if (type == 'number' || type == 'boolean' || val == null) { - return `${val}`; - } - if (type == 'string') { - return `"${val}"`; - } - if (type == 'symbol') { - const description = val.description; - if (description == null) { - return 'Symbol'; - } else { - return `Symbol(${description})`; - } - } - if (type == 'function') { - const name = val.name; - if (typeof name == 'string' && name.length > 0) { - return `Function(${name})`; - } else { - return 'Function'; - } - } - // objects - if (Array.isArray(val)) { - const length = val.length; - let debug = '['; - if (length > 0) { - debug += debugString(val[0]); - } - for(let i = 1; i < length; i++) { - debug += ', ' + debugString(val[i]); - } - debug += ']'; - return debug; - } - // Test for built-in - const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val)); - let className; - if (builtInMatches.length > 1) { - className = builtInMatches[1]; - } else { - // Failed to match the standard '[object ClassName]' - return toString.call(val); - } - if (className == 'Object') { - // we're a user defined class or Object - // JSON.stringify avoids problems with cycles, and is generally much - // easier than looping through ownProperties of `val`. - try { - return 'Object(' + JSON.stringify(val) + ')'; - } catch (_) { - return 'Object'; - } - } - // errors - if (val instanceof Error) { - return `${val.name}: ${val.message}\n${val.stack}`; - } - // TODO we could test for more things here, like `Set`s and `Map`s. - return className; -} - -const CLOSURE_DTORS = (typeof FinalizationRegistry === 'undefined') - ? { register: () => {}, unregister: () => {} } - : new FinalizationRegistry(state => { - wasm.__wbindgen_export_3.get(state.dtor)(state.a, state.b) -}); - -function makeMutClosure(arg0, arg1, dtor, f) { - const state = { a: arg0, b: arg1, cnt: 1, dtor }; - const real = (...args) => { - // First up with a closure we increment the internal reference - // count. This ensures that the Rust closure environment won't - // be deallocated while we're invoking it. - state.cnt++; - const a = state.a; - state.a = 0; - try { - return f(a, state.b, ...args); - } finally { - if (--state.cnt === 0) { - wasm.__wbindgen_export_3.get(state.dtor)(a, state.b); - CLOSURE_DTORS.unregister(state); - } else { - state.a = a; - } - } - }; - real.original = state; - CLOSURE_DTORS.register(real, state, state); - return real; -} -function __wbg_adapter_34(arg0, arg1) { - wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hfc3cd25b53215e84(arg0, arg1); -} - -function __wbg_adapter_37(arg0, arg1, arg2) { - wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h45df3e6947fcd651(arg0, arg1, addHeapObject(arg2)); -} - -function __wbg_adapter_42(arg0, arg1) { - wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hd4a56f8647b4502b(arg0, arg1); -} - -function __wbg_adapter_45(arg0, arg1) { - wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h92f8e55d458a8e39(arg0, arg1); -} - -function __wbg_adapter_48(arg0, arg1, arg2) { - wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h90985823836ef819(arg0, arg1, addHeapObject(arg2)); -} - -let stack_pointer = 128; - -function addBorrowedObject(obj) { - if (stack_pointer == 1) throw new Error('out of js stack'); - heap[--stack_pointer] = obj; - return stack_pointer; -} -function __wbg_adapter_53(arg0, arg1, arg2) { - try { - wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hff3e249b51682479(arg0, arg1, addBorrowedObject(arg2)); - } finally { - heap[stack_pointer++] = undefined; - } -} - -/** -* Automatically run after wasm is loaded. -*/ -export function main() { - wasm.main(); -} - -/** -* @returns {Promise} -*/ -export function run() { - const ret = wasm.run(); - return takeObject(ret); -} - -function handleError(f, args) { - try { - return f.apply(this, args); - } catch (e) { - wasm.__wbindgen_exn_store(addHeapObject(e)); - } -} -/** -* Entry point for web workers -* @param {number} ptr -*/ -export function wasm_thread_entry_point(ptr) { - wasm.wasm_thread_entry_point(ptr); -} - -function __wbg_adapter_218(arg0, arg1, arg2, arg3) { - wasm.wasm_bindgen__convert__closures__invoke2_mut__h808c9af25a9c04f4(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3)); -} - -function notDefined(what) { return () => { throw new Error(`${what} is not defined`); }; } - -const RpcSenderFinalization = (typeof FinalizationRegistry === 'undefined') - ? { register: () => {}, unregister: () => {} } - : new FinalizationRegistry(ptr => wasm.__wbg_rpcsender_free(ptr >>> 0, 1)); -/** -*/ -export class RpcSender { - - static __wrap(ptr) { - ptr = ptr >>> 0; - const obj = Object.create(RpcSender.prototype); - obj.__wbg_ptr = ptr; - RpcSenderFinalization.register(obj, obj.__wbg_ptr, obj); - return obj; - } - - __destroy_into_raw() { - const ptr = this.__wbg_ptr; - this.__wbg_ptr = 0; - RpcSenderFinalization.unregister(this); - return ptr; - } - - free() { - const ptr = this.__destroy_into_raw(); - wasm.__wbg_rpcsender_free(ptr, 0); - } - /** - * @returns {State} - */ - state() { - const ret = wasm.rpcsender_state(this.__wbg_ptr); - return State.__wrap(ret); - } - /** - * @returns {Stats} - */ - stats() { - const ret = wasm.rpcsender_state(this.__wbg_ptr); - return Stats.__wrap(ret); - } - /** - * @returns {Promise} - */ - status() { - const ret = wasm.rpcsender_status(this.__wbg_ptr); - return takeObject(ret); - } -} - -const StateFinalization = (typeof FinalizationRegistry === 'undefined') - ? { register: () => {}, unregister: () => {} } - : new FinalizationRegistry(ptr => wasm.__wbg_state_free(ptr >>> 0, 1)); -/** -*/ -export class State { - - static __wrap(ptr) { - ptr = ptr >>> 0; - const obj = Object.create(State.prototype); - obj.__wbg_ptr = ptr; - StateFinalization.register(obj, obj.__wbg_ptr, obj); - return obj; - } - - __destroy_into_raw() { - const ptr = this.__wbg_ptr; - this.__wbg_ptr = 0; - StateFinalization.unregister(this); - return ptr; - } - - free() { - const ptr = this.__destroy_into_raw(); - wasm.__wbg_state_free(ptr, 0); - } - /** - * @returns {Promise} - */ - peers() { - const ret = wasm.state_peers(this.__wbg_ptr); - return takeObject(ret); - } - /** - * @returns {Promise} - */ - message_progress() { - const ret = wasm.state_message_progress(this.__wbg_ptr); - return takeObject(ret); - } -} - -const StatsFinalization = (typeof FinalizationRegistry === 'undefined') - ? { register: () => {}, unregister: () => {} } - : new FinalizationRegistry(ptr => wasm.__wbg_stats_free(ptr >>> 0, 1)); -/** -*/ -export class Stats { - - static __wrap(ptr) { - ptr = ptr >>> 0; - const obj = Object.create(Stats.prototype); - obj.__wbg_ptr = ptr; - StatsFinalization.register(obj, obj.__wbg_ptr, obj); - return obj; - } - - __destroy_into_raw() { - const ptr = this.__wbg_ptr; - this.__wbg_ptr = 0; - StatsFinalization.unregister(this); - return ptr; - } - - free() { - const ptr = this.__destroy_into_raw(); - wasm.__wbg_stats_free(ptr, 0); - } - /** - * @param {number | undefined} [limit] - * @returns {Promise} - */ - sync(limit) { - const ret = wasm.stats_sync(this.__wbg_ptr, !isLikeNone(limit), isLikeNone(limit) ? 0 : limit); - return takeObject(ret); - } - /** - * @returns {Promise} - */ - block_producer() { - const ret = wasm.stats_block_producer(this.__wbg_ptr); - return takeObject(ret); - } -} - -async function __wbg_load(module, imports) { - if (typeof Response === 'function' && module instanceof Response) { - if (typeof WebAssembly.instantiateStreaming === 'function') { - try { - return await WebAssembly.instantiateStreaming(module, imports); - - } catch (e) { - if (module.headers.get('Content-Type') != 'application/wasm') { - console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e); - - } else { - throw e; - } - } - } - - const bytes = await module.arrayBuffer(); - return await WebAssembly.instantiate(bytes, imports); - - } else { - const instance = await WebAssembly.instantiate(module, imports); - - if (instance instanceof WebAssembly.Instance) { - return { instance, module }; - - } else { - return instance; - } - } -} - -function __wbg_get_imports() { - const imports = {}; - imports.wbg = {}; - imports.wbg.__wbindgen_object_drop_ref = function(arg0) { - takeObject(arg0); - }; - imports.wbg.__wbindgen_cb_drop = function(arg0) { - const obj = takeObject(arg0).original; - if (obj.cnt-- == 1) { - obj.a = 0; - return true; - } - const ret = false; - return ret; - }; - imports.wbg.__wbindgen_string_new = function(arg0, arg1) { - const ret = getStringFromWasm0(arg0, arg1); - return addHeapObject(ret); - }; - imports.wbg.__wbindgen_is_undefined = function(arg0) { - const ret = getObject(arg0) === undefined; - return ret; - }; - imports.wbg.__wbg_new_abda76e883ba8a5f = function() { - const ret = new Error(); - return addHeapObject(ret); - }; - imports.wbg.__wbg_stack_658279fe44541cf6 = function(arg0, arg1) { - const ret = getObject(arg1).stack; - const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - const len1 = WASM_VECTOR_LEN; - getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); - getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); - }; - imports.wbg.__wbg_error_f851667af71bcfc6 = function(arg0, arg1) { - let deferred0_0; - let deferred0_1; - try { - deferred0_0 = arg0; - deferred0_1 = arg1; - console.error(getStringFromWasm0(arg0, arg1)); - } finally { - wasm.__wbindgen_free(deferred0_0, deferred0_1, 1); - } - }; - imports.wbg.__wbg_rpcsender_new = function(arg0) { - const ret = RpcSender.__wrap(arg0); - return addHeapObject(ret); - }; - imports.wbg.__wbindgen_object_clone_ref = function(arg0) { - const ret = getObject(arg0); - return addHeapObject(ret); - }; - imports.wbg.__wbg_clearTimeout_541ac0980ffcef74 = function(arg0) { - const ret = clearTimeout(takeObject(arg0)); - return addHeapObject(ret); - }; - imports.wbg.__wbg_setTimeout_7d81d052875b0f4f = function() { return handleError(function (arg0, arg1) { - const ret = setTimeout(getObject(arg0), arg1); - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_waitAsync_cd62c81646382b45 = function() { - const ret = Atomics.waitAsync; - return addHeapObject(ret); - }; - imports.wbg.__wbg_waitAsync_3ed212d5e9450545 = function(arg0, arg1, arg2) { - const ret = Atomics.waitAsync(getObject(arg0), arg1 >>> 0, arg2); - return addHeapObject(ret); - }; - imports.wbg.__wbg_async_49a1efd7e3e4bd73 = function(arg0) { - const ret = getObject(arg0).async; - return ret; - }; - imports.wbg.__wbg_value_96cb463707ad2f31 = function(arg0) { - const ret = getObject(arg0).value; - return addHeapObject(ret); - }; - imports.wbg.__wbindgen_link_8b58b27602368eaa = function(arg0) { - const val = `onmessage = function (ev) { - let [ia, index, value] = ev.data; - ia = new Int32Array(ia.buffer); - let result = Atomics.wait(ia, index, value); - postMessage(result); - }; - `; - const ret = typeof URL.createObjectURL === 'undefined' ? "data:application/javascript," + encodeURIComponent(val) : URL.createObjectURL(new Blob([val], { type: "text/javascript" })); - const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - const len1 = WASM_VECTOR_LEN; - getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); - getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); - }; - imports.wbg.__wbindgen_number_new = function(arg0) { - const ret = arg0; - return addHeapObject(ret); - }; - imports.wbg.__wbg_queueMicrotask_12a30234db4045d3 = function(arg0) { - queueMicrotask(getObject(arg0)); - }; - imports.wbg.__wbg_queueMicrotask_48421b3cc9052b68 = function(arg0) { - const ret = getObject(arg0).queueMicrotask; - return addHeapObject(ret); - }; - imports.wbg.__wbindgen_is_function = function(arg0) { - const ret = typeof(getObject(arg0)) === 'function'; - return ret; - }; - imports.wbg.__wbg_crypto_1d1f22824a6a080c = function(arg0) { - const ret = getObject(arg0).crypto; - return addHeapObject(ret); - }; - imports.wbg.__wbindgen_is_object = function(arg0) { - const val = getObject(arg0); - const ret = typeof(val) === 'object' && val !== null; - return ret; - }; - imports.wbg.__wbg_process_4a72847cc503995b = function(arg0) { - const ret = getObject(arg0).process; - return addHeapObject(ret); - }; - imports.wbg.__wbg_versions_f686565e586dd935 = function(arg0) { - const ret = getObject(arg0).versions; - return addHeapObject(ret); - }; - imports.wbg.__wbg_node_104a2ff8d6ea03a2 = function(arg0) { - const ret = getObject(arg0).node; - return addHeapObject(ret); - }; - imports.wbg.__wbindgen_is_string = function(arg0) { - const ret = typeof(getObject(arg0)) === 'string'; - return ret; - }; - imports.wbg.__wbg_require_cca90b1a94a0255b = function() { return handleError(function () { - const ret = module.require; - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_msCrypto_eb05e62b530a1508 = function(arg0) { - const ret = getObject(arg0).msCrypto; - return addHeapObject(ret); - }; - imports.wbg.__wbg_randomFillSync_5c9c955aa56b6049 = function() { return handleError(function (arg0, arg1) { - getObject(arg0).randomFillSync(takeObject(arg1)); - }, arguments) }; - imports.wbg.__wbg_getRandomValues_3aa56aa6edec874c = function() { return handleError(function (arg0, arg1) { - getObject(arg0).getRandomValues(getObject(arg1)); - }, arguments) }; - imports.wbg.__wbindgen_number_get = function(arg0, arg1) { - const obj = getObject(arg1); - const ret = typeof(obj) === 'number' ? obj : undefined; - getDataViewMemory0().setFloat64(arg0 + 8 * 1, isLikeNone(ret) ? 0 : ret, true); - getDataViewMemory0().setInt32(arg0 + 4 * 0, !isLikeNone(ret), true); - }; - imports.wbg.__wbindgen_string_get = function(arg0, arg1) { - const obj = getObject(arg1); - const ret = typeof(obj) === 'string' ? obj : undefined; - var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - var len1 = WASM_VECTOR_LEN; - getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); - getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); - }; - imports.wbg.__wbg_instanceof_Window_9029196b662bc42a = function(arg0) { - let result; - try { - result = getObject(arg0) instanceof Window; - } catch (_) { - result = false; - } - const ret = result; - return ret; - }; - imports.wbg.__wbg_navigator_7c9103698acde322 = function(arg0) { - const ret = getObject(arg0).navigator; - return addHeapObject(ret); - }; - imports.wbg.__wbg_fetch_336b6f0cb426b46e = function(arg0, arg1) { - const ret = getObject(arg0).fetch(getObject(arg1)); - return addHeapObject(ret); - }; - imports.wbg.__wbg_instanceof_WorkerGlobalScope_d9d741da0fb130ce = function(arg0) { - let result; - try { - result = getObject(arg0) instanceof WorkerGlobalScope; - } catch (_) { - result = false; - } - const ret = result; - return ret; - }; - imports.wbg.__wbg_navigator_41bd88b80ed4685e = function(arg0) { - const ret = getObject(arg0).navigator; - return addHeapObject(ret); - }; - imports.wbg.__wbg_set_b34caba58723c454 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { - getObject(arg0).set(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4)); - }, arguments) }; - imports.wbg.__wbg_setonmessage_f0bd0280573b7084 = function(arg0, arg1) { - getObject(arg0).onmessage = getObject(arg1); - }; - imports.wbg.__wbg_new_8e7322f46d5d019c = function() { return handleError(function (arg0, arg1) { - const ret = new Worker(getStringFromWasm0(arg0, arg1)); - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_newwithoptions_1bd20b45061ed935 = function() { return handleError(function (arg0, arg1, arg2) { - const ret = new Worker(getStringFromWasm0(arg0, arg1), getObject(arg2)); - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_postMessage_8c609e2bde333d9c = function() { return handleError(function (arg0, arg1) { - getObject(arg0).postMessage(getObject(arg1)); - }, arguments) }; - imports.wbg.__wbg_hardwareConcurrency_af3a0cb6b3464bd9 = function(arg0) { - const ret = getObject(arg0).hardwareConcurrency; - return ret; - }; - imports.wbg.__wbg_localDescription_60b438182ca37beb = function(arg0) { - const ret = getObject(arg0).localDescription; - return isLikeNone(ret) ? 0 : addHeapObject(ret); - }; - imports.wbg.__wbg_iceGatheringState_fea35c457cf86f05 = function(arg0) { - const ret = getObject(arg0).iceGatheringState; - return {"new":0,"gathering":1,"complete":2,}[ret] ?? 3; - }; - imports.wbg.__wbg_connectionState_915abee2c4db3016 = function(arg0) { - const ret = getObject(arg0).connectionState; - return {"closed":0,"failed":1,"disconnected":2,"new":3,"connecting":4,"connected":5,}[ret] ?? 6; - }; - imports.wbg.__wbg_setonicegatheringstatechange_e0c5a4ab4d37ab63 = function(arg0, arg1) { - getObject(arg0).onicegatheringstatechange = getObject(arg1); - }; - imports.wbg.__wbg_setonconnectionstatechange_98879070c908305e = function(arg0, arg1) { - getObject(arg0).onconnectionstatechange = getObject(arg1); - }; - imports.wbg.__wbg_newwithconfiguration_c2620a61f13be424 = function() { return handleError(function (arg0) { - const ret = new RTCPeerConnection(getObject(arg0)); - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_close_ade28656aea74a4b = function(arg0) { - getObject(arg0).close(); - }; - imports.wbg.__wbg_createAnswer_ffe6dbcf7cd5ed2a = function(arg0) { - const ret = getObject(arg0).createAnswer(); - return addHeapObject(ret); - }; - imports.wbg.__wbg_createDataChannel_69cc16b4f9cad344 = function(arg0, arg1, arg2, arg3) { - const ret = getObject(arg0).createDataChannel(getStringFromWasm0(arg1, arg2), getObject(arg3)); - return addHeapObject(ret); - }; - imports.wbg.__wbg_createOffer_aa7098f1f4c2f40b = function(arg0) { - const ret = getObject(arg0).createOffer(); - return addHeapObject(ret); - }; - imports.wbg.__wbg_setLocalDescription_4744eb2c267efbb4 = function(arg0, arg1) { - const ret = getObject(arg0).setLocalDescription(getObject(arg1)); - return addHeapObject(ret); - }; - imports.wbg.__wbg_setRemoteDescription_0c7a66e1bd51121d = function(arg0, arg1) { - const ret = getObject(arg0).setRemoteDescription(getObject(arg1)); - return addHeapObject(ret); - }; - imports.wbg.__wbg_data_ab99ae4a2e1e8bc9 = function(arg0) { - const ret = getObject(arg0).data; - return addHeapObject(ret); - }; - imports.wbg.__wbg_headers_b439dcff02e808e5 = function(arg0) { - const ret = getObject(arg0).headers; - return addHeapObject(ret); - }; - imports.wbg.__wbg_newwithstrandinit_cad5cd6038c7ff5d = function() { return handleError(function (arg0, arg1, arg2) { - const ret = new Request(getStringFromWasm0(arg0, arg1), getObject(arg2)); - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_instanceof_DedicatedWorkerGlobalScope_936e3c64be605b1e = function(arg0) { - let result; - try { - result = getObject(arg0) instanceof DedicatedWorkerGlobalScope; - } catch (_) { - result = false; - } - const ret = result; - return ret; - }; - imports.wbg.__wbg_postMessage_2f0b8369b84c3c1e = function() { return handleError(function (arg0, arg1) { - getObject(arg0).postMessage(getObject(arg1)); - }, arguments) }; - imports.wbg.__wbg_now_0cfdc90c97d0c24b = function(arg0) { - const ret = getObject(arg0).now(); - return ret; - }; - imports.wbg.__wbg_setonopen_37846cc10560e3c0 = function(arg0, arg1) { - getObject(arg0).onopen = getObject(arg1); - }; - imports.wbg.__wbg_setonerror_de2acc8492751dad = function(arg0, arg1) { - getObject(arg0).onerror = getObject(arg1); - }; - imports.wbg.__wbg_setonclose_d39802b4195bab2f = function(arg0, arg1) { - getObject(arg0).onclose = getObject(arg1); - }; - imports.wbg.__wbg_setonmessage_463c6aefedd50235 = function(arg0, arg1) { - getObject(arg0).onmessage = getObject(arg1); - }; - imports.wbg.__wbg_close_4df98968ad72ccde = function(arg0) { - getObject(arg0).close(); - }; - imports.wbg.__wbg_send_1e6563347168b789 = function() { return handleError(function (arg0, arg1) { - getObject(arg0).send(getObject(arg1)); - }, arguments) }; - imports.wbg.__wbg_instanceof_Response_fc4327dbfcdf5ced = function(arg0) { - let result; - try { - result = getObject(arg0) instanceof Response; - } catch (_) { - result = false; - } - const ret = result; - return ret; - }; - imports.wbg.__wbg_json_2a46ed5b7c4d30d1 = function() { return handleError(function (arg0) { - const ret = getObject(arg0).json(); - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_size_b9bc39a333bd5d88 = function(arg0) { - const ret = getObject(arg0).size; - return ret; - }; - imports.wbg.__wbg_newwithstrsequence_6b9d515005eb94ac = function() { return handleError(function (arg0) { - const ret = new Blob(getObject(arg0)); - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_slice_db5bccebb10de3fb = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { - const ret = getObject(arg0).slice(arg1, arg2, getStringFromWasm0(arg3, arg4)); - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_createObjectURL_d82f2880bada6a1d = function() { return handleError(function (arg0, arg1) { - const ret = URL.createObjectURL(getObject(arg1)); - const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - const len1 = WASM_VECTOR_LEN; - getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); - getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); - }, arguments) }; - imports.wbg.__wbg_hardwareConcurrency_3b217d60cc0aa1a6 = function(arg0) { - const ret = getObject(arg0).hardwareConcurrency; - return ret; - }; - imports.wbg.__wbg_sdp_997ce3396a98ebc3 = function(arg0, arg1) { - const ret = getObject(arg1).sdp; - const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - const len1 = WASM_VECTOR_LEN; - getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); - getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); - }; - imports.wbg.__wbg_new_a220cf903aa02ca2 = function() { - const ret = new Array(); - return addHeapObject(ret); - }; - imports.wbg.__wbg_newnoargs_76313bd6ff35d0f2 = function(arg0, arg1) { - const ret = new Function(getStringFromWasm0(arg0, arg1)); - return addHeapObject(ret); - }; - imports.wbg.__wbg_get_224d16597dbbfd96 = function() { return handleError(function (arg0, arg1) { - const ret = Reflect.get(getObject(arg0), getObject(arg1)); - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_call_1084a111329e68ce = function() { return handleError(function (arg0, arg1) { - const ret = getObject(arg0).call(getObject(arg1)); - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_new_525245e2b9901204 = function() { - const ret = new Object(); - return addHeapObject(ret); - }; - imports.wbg.__wbg_self_3093d5d1f7bcb682 = function() { return handleError(function () { - const ret = self.self; - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_window_3bcfc4d31bc012f8 = function() { return handleError(function () { - const ret = window.window; - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_globalThis_86b222e13bdf32ed = function() { return handleError(function () { - const ret = globalThis.globalThis; - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_global_e5a3fe56f8be9485 = function() { return handleError(function () { - const ret = global.global; - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_eval_6e4fc17d87772f52 = function() { return handleError(function (arg0, arg1) { - const ret = eval(getStringFromWasm0(arg0, arg1)); - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_set_673dda6c73d19609 = function(arg0, arg1, arg2) { - getObject(arg0)[arg1 >>> 0] = takeObject(arg2); - }; - imports.wbg.__wbg_of_61f336d7eeabfca8 = function(arg0, arg1, arg2) { - const ret = Array.of(getObject(arg0), getObject(arg1), getObject(arg2)); - return addHeapObject(ret); - }; - imports.wbg.__wbg_push_37c89022f34c01ca = function(arg0, arg1) { - const ret = getObject(arg0).push(getObject(arg1)); - return ret; - }; - imports.wbg.__wbg_instanceof_ArrayBuffer_61dfc3198373c902 = function(arg0) { - let result; - try { - result = getObject(arg0) instanceof ArrayBuffer; - } catch (_) { - result = false; - } - const ret = result; - return ret; - }; - imports.wbg.__wbg_call_89af060b4e1523f2 = function() { return handleError(function (arg0, arg1, arg2) { - const ret = getObject(arg0).call(getObject(arg1), getObject(arg2)); - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_now_b7a162010a9e75b4 = function() { - const ret = Date.now(); - return ret; - }; - imports.wbg.__wbg_new_b85e72ed1bfd57f9 = function(arg0, arg1) { - try { - var state0 = {a: arg0, b: arg1}; - var cb0 = (arg0, arg1) => { - const a = state0.a; - state0.a = 0; - try { - return __wbg_adapter_218(a, state0.b, arg0, arg1); - } finally { - state0.a = a; - } - }; - const ret = new Promise(cb0); - return addHeapObject(ret); - } finally { - state0.a = state0.b = 0; - } - }; - imports.wbg.__wbg_resolve_570458cb99d56a43 = function(arg0) { - const ret = Promise.resolve(getObject(arg0)); - return addHeapObject(ret); - }; - imports.wbg.__wbg_then_95e6edc0f89b73b1 = function(arg0, arg1) { - const ret = getObject(arg0).then(getObject(arg1)); - return addHeapObject(ret); - }; - imports.wbg.__wbg_then_876bb3c633745cc6 = function(arg0, arg1, arg2) { - const ret = getObject(arg0).then(getObject(arg1), getObject(arg2)); - return addHeapObject(ret); - }; - imports.wbg.__wbg_buffer_b7b08af79b0b0974 = function(arg0) { - const ret = getObject(arg0).buffer; - return addHeapObject(ret); - }; - imports.wbg.__wbg_new_a0719a520adfdb99 = function(arg0) { - const ret = new Int32Array(getObject(arg0)); - return addHeapObject(ret); - }; - imports.wbg.__wbg_newwithbyteoffsetandlength_8a2cb9ca96b27ec9 = function(arg0, arg1, arg2) { - const ret = new Uint8Array(getObject(arg0), arg1 >>> 0, arg2 >>> 0); - return addHeapObject(ret); - }; - imports.wbg.__wbg_new_ea1883e1e5e86686 = function(arg0) { - const ret = new Uint8Array(getObject(arg0)); - return addHeapObject(ret); - }; - imports.wbg.__wbg_set_d1e79e2388520f18 = function(arg0, arg1, arg2) { - getObject(arg0).set(getObject(arg1), arg2 >>> 0); - }; - imports.wbg.__wbg_length_8339fcf5d8ecd12e = function(arg0) { - const ret = getObject(arg0).length; - return ret; - }; - imports.wbg.__wbg_newwithlength_ec548f448387c968 = function(arg0) { - const ret = new Uint8Array(arg0 >>> 0); - return addHeapObject(ret); - }; - imports.wbg.__wbg_buffer_0710d1b9dbe2eea6 = function(arg0) { - const ret = getObject(arg0).buffer; - return addHeapObject(ret); - }; - imports.wbg.__wbg_subarray_7c2e3576afe181d1 = function(arg0, arg1, arg2) { - const ret = getObject(arg0).subarray(arg1 >>> 0, arg2 >>> 0); - return addHeapObject(ret); - }; - imports.wbg.__wbg_random_4a6f48b07d1eab14 = typeof Math.random == 'function' ? Math.random : notDefined('Math.random'); - imports.wbg.__wbg_set_eacc7d73fefaafdf = function() { return handleError(function (arg0, arg1, arg2) { - const ret = Reflect.set(getObject(arg0), getObject(arg1), getObject(arg2)); - return ret; - }, arguments) }; - imports.wbg.__wbg_parse_52202f117ec9ecfa = function() { return handleError(function (arg0, arg1) { - const ret = JSON.parse(getStringFromWasm0(arg0, arg1)); - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_stringify_bbf45426c92a6bf5 = function() { return handleError(function (arg0) { - const ret = JSON.stringify(getObject(arg0)); - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_mark_40e050a77cc39fea = function(arg0, arg1) { - performance.mark(getStringFromWasm0(arg0, arg1)); - }; - imports.wbg.__wbg_log_c9486ca5d8e2cbe8 = function(arg0, arg1) { - let deferred0_0; - let deferred0_1; - try { - deferred0_0 = arg0; - deferred0_1 = arg1; - console.log(getStringFromWasm0(arg0, arg1)); - } finally { - wasm.__wbindgen_free(deferred0_0, deferred0_1, 1); - } - }; - imports.wbg.__wbg_log_aba5996d9bde071f = function(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) { - let deferred0_0; - let deferred0_1; - try { - deferred0_0 = arg0; - deferred0_1 = arg1; - console.log(getStringFromWasm0(arg0, arg1), getStringFromWasm0(arg2, arg3), getStringFromWasm0(arg4, arg5), getStringFromWasm0(arg6, arg7)); - } finally { - wasm.__wbindgen_free(deferred0_0, deferred0_1, 1); - } - }; - imports.wbg.__wbg_measure_aa7a73f17813f708 = function() { return handleError(function (arg0, arg1, arg2, arg3) { - let deferred0_0; - let deferred0_1; - let deferred1_0; - let deferred1_1; - try { - deferred0_0 = arg0; - deferred0_1 = arg1; - deferred1_0 = arg2; - deferred1_1 = arg3; - performance.measure(getStringFromWasm0(arg0, arg1), getStringFromWasm0(arg2, arg3)); - } finally { - wasm.__wbindgen_free(deferred0_0, deferred0_1, 1); - wasm.__wbindgen_free(deferred1_0, deferred1_1, 1); - } - }, arguments) }; - imports.wbg.__wbindgen_debug_string = function(arg0, arg1) { - const ret = debugString(getObject(arg1)); - const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - const len1 = WASM_VECTOR_LEN; - getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); - getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); - }; - imports.wbg.__wbindgen_throw = function(arg0, arg1) { - throw new Error(getStringFromWasm0(arg0, arg1)); - }; - imports.wbg.__wbindgen_rethrow = function(arg0) { - throw takeObject(arg0); - }; - imports.wbg.__wbindgen_module = function() { - const ret = __wbg_init.__wbindgen_wasm_module; - return addHeapObject(ret); - }; - imports.wbg.__wbindgen_memory = function() { - const ret = wasm.memory; - return addHeapObject(ret); - }; - imports.wbg.__wbindgen_closure_wrapper1266 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 186, __wbg_adapter_34); - return addHeapObject(ret); - }; - imports.wbg.__wbindgen_closure_wrapper1268 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 186, __wbg_adapter_37); - return addHeapObject(ret); - }; - imports.wbg.__wbindgen_closure_wrapper1270 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 186, __wbg_adapter_37); - return addHeapObject(ret); - }; - imports.wbg.__wbindgen_closure_wrapper14345 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 4390, __wbg_adapter_42); - return addHeapObject(ret); - }; - imports.wbg.__wbindgen_closure_wrapper14884 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 4553, __wbg_adapter_45); - return addHeapObject(ret); - }; - imports.wbg.__wbindgen_closure_wrapper14934 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 4580, __wbg_adapter_48); - return addHeapObject(ret); - }; - imports.wbg.__wbindgen_closure_wrapper14936 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 4580, __wbg_adapter_48); - return addHeapObject(ret); - }; - imports.wbg.__wbindgen_closure_wrapper16260 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 5044, __wbg_adapter_53); - return addHeapObject(ret); - }; - imports['./snippets/p2p-5e5eda2a182dce1e/src/service_impl/webrtc/web.js'] = __wbg_star0; - imports['./snippets/wasm_thread-8ee53d0673203880/src/wasm32/js/module_workers_polyfill.min.js'] = __wbg_star1; - - return imports; -} - -function __wbg_init_memory(imports, memory) { - imports.wbg.memory = memory || new WebAssembly.Memory({initial:170,maximum:16384,shared:true}); -} - -function __wbg_finalize_init(instance, module, thread_stack_size) { - wasm = instance.exports; - __wbg_init.__wbindgen_wasm_module = module; - cachedDataViewMemory0 = null; - cachedUint8ArrayMemory0 = null; - -if (typeof thread_stack_size !== 'undefined' && (typeof thread_stack_size !== 'number' || thread_stack_size === 0 || thread_stack_size % 65536 !== 0)) { throw 'invalid stack size' } -wasm.__wbindgen_start(thread_stack_size); -return wasm; -} - -function initSync(module, memory) { - if (wasm !== undefined) return wasm; - - let thread_stack_size - if (typeof module !== 'undefined' && Object.getPrototypeOf(module) === Object.prototype) - ({module, memory, thread_stack_size} = module) - else - console.warn('using deprecated parameters for `initSync()`; pass a single object instead') - - const imports = __wbg_get_imports(); - - __wbg_init_memory(imports, memory); - - if (!(module instanceof WebAssembly.Module)) { - module = new WebAssembly.Module(module); - } - - const instance = new WebAssembly.Instance(module, imports); - - return __wbg_finalize_init(instance, module, thread_stack_size); -} - -async function __wbg_init(module_or_path, memory) { - if (wasm !== undefined) return wasm; - - let thread_stack_size - if (typeof module_or_path !== 'undefined' && Object.getPrototypeOf(module_or_path) === Object.prototype) - ({module_or_path, memory, thread_stack_size} = module_or_path) - else - console.warn('using deprecated parameters for the initialization function; pass a single object instead') - - if (typeof module_or_path === 'undefined') { - module_or_path = new URL('openmina_node_web_bg.wasm', import.meta.url); - } - const imports = __wbg_get_imports(); - - if (typeof module_or_path === 'string' || (typeof Request === 'function' && module_or_path instanceof Request) || (typeof URL === 'function' && module_or_path instanceof URL)) { - module_or_path = fetch(module_or_path); - } - - __wbg_init_memory(imports, memory); - - const { instance, module } = await __wbg_load(await module_or_path, imports); - - return __wbg_finalize_init(instance, module, thread_stack_size); -} - -export { initSync }; -export default __wbg_init; diff --git a/frontend/src/assets/webnode/pkg/openmina_node_web_bg.wasm b/frontend/src/assets/webnode/pkg/openmina_node_web_bg.wasm deleted file mode 100644 index 927f5014d0..0000000000 Binary files a/frontend/src/assets/webnode/pkg/openmina_node_web_bg.wasm and /dev/null differ diff --git a/frontend/src/assets/webnode/pkg/openmina_node_web_bg.wasm.d.ts b/frontend/src/assets/webnode/pkg/openmina_node_web_bg.wasm.d.ts deleted file mode 100644 index 0ecafcda48..0000000000 --- a/frontend/src/assets/webnode/pkg/openmina_node_web_bg.wasm.d.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* tslint:disable */ -/* eslint-disable */ -export function main(): void; -export function run(): number; -export function stats_sync(a: number, b: number, c: number): number; -export function stats_block_producer(a: number): number; -export function __wbg_state_free(a: number, b: number): void; -export function state_peers(a: number): number; -export function state_message_progress(a: number): number; -export function __wbg_stats_free(a: number, b: number): void; -export function __wbg_rpcsender_free(a: number, b: number): void; -export function rpcsender_state(a: number): number; -export function rpcsender_status(a: number): number; -export function rpcsender_stats(a: number): number; -export function wasm_thread_entry_point(a: number): void; -export const memory: WebAssembly.Memory; -export function __wbindgen_malloc(a: number, b: number): number; -export function __wbindgen_realloc(a: number, b: number, c: number, d: number): number; -export const __wbindgen_export_3: WebAssembly.Table; -export function _dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hfc3cd25b53215e84(a: number, b: number): void; -export function _dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h45df3e6947fcd651(a: number, b: number, c: number): void; -export function _dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hd4a56f8647b4502b(a: number, b: number): void; -export function _dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h92f8e55d458a8e39(a: number, b: number): void; -export function _dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h90985823836ef819(a: number, b: number, c: number): void; -export function _dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hff3e249b51682479(a: number, b: number, c: number): void; -export function __wbindgen_free(a: number, b: number, c: number): void; -export function __wbindgen_exn_store(a: number): void; -export function wasm_bindgen__convert__closures__invoke2_mut__h808c9af25a9c04f4(a: number, b: number, c: number, d: number): void; -export function __wbindgen_thread_destroy(a: number, b: number, c: number): void; -export function __wbindgen_start(a: number): void; diff --git a/frontend/src/assets/webnode/pkg/snippets/p2p-5e5eda2a182dce1e/src/service_impl/webrtc/web.js b/frontend/src/assets/webnode/pkg/snippets/p2p-5e5eda2a182dce1e/src/service_impl/webrtc/web.js deleted file mode 100644 index ea6963c1dc..0000000000 --- a/frontend/src/assets/webnode/pkg/snippets/p2p-5e5eda2a182dce1e/src/service_impl/webrtc/web.js +++ /dev/null @@ -1,17 +0,0 @@ -// https://bugs.chromium.org/p/chromium/issues/detail?id=825576 -// workaround: https://stackoverflow.com/questions/66546934/how-to-clear-closed-rtcpeerconnection-with-workaround -export function webrtcCleanup() { - queueMicrotask(() => { - console.warn("[WebRTC] doing heavy (around 50ms) GC for dangling peer connections"); - let img = document.createElement("img"); - img.src = window.URL.createObjectURL(new Blob([new ArrayBuffer(5e+7)])); // 50Mo or less or more depending as you wish to force/invoke GC cycle run - img.onerror = function() { - window.URL.revokeObjectURL(this.src); - img = null - } - }); -} - -export function schedulePeriodicWebrtcCleanup() { - setInterval(webrtcCleanup, 60 * 1000); -} diff --git a/frontend/src/assets/webnode/pkg/snippets/p2p-b52ece2615728d9c/src/service_impl/webrtc/web.js b/frontend/src/assets/webnode/pkg/snippets/p2p-b52ece2615728d9c/src/service_impl/webrtc/web.js deleted file mode 100644 index ea6963c1dc..0000000000 --- a/frontend/src/assets/webnode/pkg/snippets/p2p-b52ece2615728d9c/src/service_impl/webrtc/web.js +++ /dev/null @@ -1,17 +0,0 @@ -// https://bugs.chromium.org/p/chromium/issues/detail?id=825576 -// workaround: https://stackoverflow.com/questions/66546934/how-to-clear-closed-rtcpeerconnection-with-workaround -export function webrtcCleanup() { - queueMicrotask(() => { - console.warn("[WebRTC] doing heavy (around 50ms) GC for dangling peer connections"); - let img = document.createElement("img"); - img.src = window.URL.createObjectURL(new Blob([new ArrayBuffer(5e+7)])); // 50Mo or less or more depending as you wish to force/invoke GC cycle run - img.onerror = function() { - window.URL.revokeObjectURL(this.src); - img = null - } - }); -} - -export function schedulePeriodicWebrtcCleanup() { - setInterval(webrtcCleanup, 60 * 1000); -} diff --git a/frontend/src/assets/webnode/pkg/snippets/wasm-bindgen-futures-a509390b5b548b61/src/task/worker.js b/frontend/src/assets/webnode/pkg/snippets/wasm-bindgen-futures-a509390b5b548b61/src/task/worker.js deleted file mode 100644 index d25dab6606..0000000000 --- a/frontend/src/assets/webnode/pkg/snippets/wasm-bindgen-futures-a509390b5b548b61/src/task/worker.js +++ /dev/null @@ -1,6 +0,0 @@ -onmessage = function (ev) { - let [ia, index, value] = ev.data; - ia = new Int32Array(ia.buffer); - let result = Atomics.wait(ia, index, value); - postMessage(result); -}; diff --git a/frontend/src/assets/webnode/pkg/snippets/wasm_thread-8ee53d0673203880/src/wasm32/js/module_workers_polyfill.min.js b/frontend/src/assets/webnode/pkg/snippets/wasm_thread-8ee53d0673203880/src/wasm32/js/module_workers_polyfill.min.js deleted file mode 100644 index 3ef050e317..0000000000 --- a/frontend/src/assets/webnode/pkg/snippets/wasm_thread-8ee53d0673203880/src/wasm32/js/module_workers_polyfill.min.js +++ /dev/null @@ -1,8 +0,0 @@ -export function load_module_workers_polyfill() { - if(Worker._$P !== true) { - let polyfill = "!function(e){if(!e||!0!==e._$P){if(e){var n,r=Object.defineProperty({},\"type\",{get:function(){n=!0}});try{var t=URL.createObjectURL(new Blob([\"\"],{type:\"text/javascript\"}));new e(t,r).terminate(),URL.revokeObjectURL(t)}catch(e){}if(!n)try{new e(\"data:text/javascript,\",r).terminate()}catch(e){}if(n)return;(self.Worker=function(n,r){return r&&\"module\"==r.type&&(r={name:n+\"\\n\"+(r.name||\"\")},n=\"undefined\"==typeof document?location.href:document.currentScript&&document.currentScript.src||(new Error).stack.match(/[(@]((file|https?):\\/\\/[^)]+?):\\d+(:\\d+)?(?:\\)|$)/m)[1]),new e(n,r)})._$P=!0}\"undefined\"==typeof document&&function(){var e={},n={};function r(e,n){for(n=n.replace(/^(\\.\\.\\/|\\.\\/)/,e.replace(/[^/]+$/g,\"\")+\"$1\");n!==(n=n.replace(/[^/]+\\/\\.\\.\\//g,\"\")););return n.replace(/\\.\\//g,\"\")}var t=[],s=t.push.bind(t);addEventListener(\"message\",s);var a=self.name.match(/^[^\\n]+/)[0];self.name=self.name.replace(/^[^\\n]*\\n/g,\"\"),function t(s,a){var u,o=s;return a&&(s=r(a,s)),e[s]||(e[s]=fetch(s).then((function(a){if((o=a.url)!==s){if(null!=e[o])return e[o];e[o]=e[s]}return a.text().then((function(e){if(!a.ok)throw e;var c={exports:{}};u=n[o]||(n[o]=c.exports);var i=function(e){return t(e,o)},f=[];return e=function(e,n){n=n||[];var r,t=[],a=0;function u(e,n){for(var s,a=/(?:^|,)\\s*([\\w$]+)(?:\\s+as\\s+([\\w$]+))?\\s*/g,u=[];s=a.exec(e);)n?t.push((s[2]||s[1])+\":\"+s[1]):u.push((s[2]||s[1])+\"=\"+r+\".\"+s[1]);return u}return(e=e.replace(/(^\\s*|[;}\\s\\n]\\s*)import\\s*(?:(?:([\\w$]+)(?:\\s*\\,\\s*\\{([^}]+)\\})?|(?:\\*\\s*as\\s+([\\w$]+))|\\{([^}]*)\\})\\s*from)?\\s*(['\"])(.+?)\\6/g,(function(e,t,s,o,c,i,f,p){return n.push(p),t+=\"var \"+(r=\"$im$\"+ ++a)+\"=$require(\"+f+p+f+\")\",s&&(t+=\";var \"+s+\" = 'default' in \"+r+\" ? \"+r+\".default : \"+r),c&&(t+=\";var \"+c+\" = \"+r),(o=o||i)&&(t+=\";var \"+u(o,!1)),t})).replace(/((?:^|[;}\\s\\n])\\s*)export\\s*(?:\\s+(default)\\s+|((?:async\\s+)?function\\s*\\*?|class|const\\s|let\\s|var\\s)\\s*([a-zA-Z0-9$_{[]+))/g,(function(e,n,r,s,u){if(r){var o=\"$im$\"+ ++a;return t.push(\"default:\"+o),n+\"var \"+o+\"=\"}return t.push(u+\":\"+u),n+s+\" \"+u})).replace(/((?:^|[;}\\s\\n])\\s*)export\\s*\\{([^}]+)\\}\\s*;?/g,(function(e,n,r){return u(r,!0),n})).replace(/((?:^|[^a-zA-Z0-9$_@`'\".])\\s*)(import\\s*\\([\\s\\S]+?\\))/g,\"$1$$$2\")).replace(/((?:^|[^a-zA-Z0-9$_@`'\".])\\s*)import\\.meta\\.url/g,\"$1\"+JSON.stringify(s))+\"\\n$module.exports={\"+t.join(\",\")+\"}\"}(e,f),Promise.all(f.map((function(e){var s=r(o,e);return s in n?n[s]:t(s)}))).then((function(n){e+=\"\\n//# sourceURL=\"+s;try{var r=new Function(\"$import\",\"$require\",\"$module\",\"$exports\",e)}catch(n){var t=n.line-1,a=n.column,o=e.split(\"\\n\"),p=(o[t-2]||\"\")+\"\\n\"+o[t-1]+\"\\n\"+(null==a?\"\":new Array(a).join(\"-\")+\"^\\n\")+(o[t]||\"\"),l=new Error(n.message+\"\\n\\n\"+p,s,t);throw l.sourceURL=l.fileName=s,l.line=t,l.column=a,l}var m=r(i,(function(e){return n[f.indexOf(e)]}),c,c.exports);return null!=m&&(c.exports=m),Object.assign(u,c.exports),c.exports}))}))})))}(a).then((function(){removeEventListener(\"message\",s),t.map(dispatchEvent)})).catch((function(e){setTimeout((function(){throw e}))}))}()}}(self.Worker);"; - let blob = new Blob([polyfill], { type: 'text/javascript' }); - let blobUrl = URL.createObjectURL(blob); - !function(e){if(!e||!0!==e._$P){if(e){var n,r=Object.defineProperty({},"type",{get:function(){n=!0}});try{var t=URL.createObjectURL(new Blob([""],{type:"text/javascript"}));new e(t,r).terminate(),URL.revokeObjectURL(t)}catch(e){}if(!n)try{new e("data:text/javascript,",r).terminate()}catch(e){}if(n)return;(self.Worker=function(n,r){return r&&"module"==r.type&&(r={name:n+"\n"+(r.name||"")},n=blobUrl),new e(n,r)})._$P=!0}"undefined"==typeof document&&function(){var e={},n={};function r(e,n){for(n=n.replace(/^(\.\.\/|\.\/)/,e.replace(/[^/]+$/g,"")+"$1");n!==(n=n.replace(/[^/]+\/\.\.\//g,"")););return n.replace(/\.\//g,"")}var t=[],s=t.push.bind(t);addEventListener("message",s);var a=self.name.match(/^[^\n]+/)[0];self.name=self.name.replace(/^[^\n]*\n/g,""),function t(s,a){var u,o=s;return a&&(s=r(a,s)),e[s]||(e[s]=fetch(s).then((function(a){if((o=a.url)!==s){if(null!=e[o])return e[o];e[o]=e[s]}return a.text().then((function(e){if(!a.ok)throw e;var c={exports:{}};u=n[o]||(n[o]=c.exports);var i=function(e){return t(e,o)},f=[];return e=function(e,n){n=n||[];var r,t=[],a=0;function u(e,n){for(var s,a=/(?:^|,)\s*([\w$]+)(?:\s+as\s+([\w$]+))?\s*/g,u=[];s=a.exec(e);)n?t.push((s[2]||s[1])+":"+s[1]):u.push((s[2]||s[1])+"="+r+"."+s[1]);return u}return(e=e.replace(/(^\s*|[;}\s\n]\s*)import\s*(?:(?:([\w$]+)(?:\s*\,\s*\{([^}]+)\})?|(?:\*\s*as\s+([\w$]+))|\{([^}]*)\})\s*from)?\s*(['"])(.+?)\6/g,(function(e,t,s,o,c,i,f,p){return n.push(p),t+="var "+(r="$im$"+ ++a)+"=$require("+f+p+f+")",s&&(t+=";var "+s+" = 'default' in "+r+" ? "+r+".default : "+r),c&&(t+=";var "+c+" = "+r),(o=o||i)&&(t+=";var "+u(o,!1)),t})).replace(/((?:^|[;}\s\n])\s*)export\s*(?:\s+(default)\s+|((?:async\s+)?function\s*\*?|class|const\s|let\s|var\s)\s*([a-zA-Z0-9$_{[]+))/g,(function(e,n,r,s,u){if(r){var o="$im$"+ ++a;return t.push("default:"+o),n+"var "+o+"="}return t.push(u+":"+u),n+s+" "+u})).replace(/((?:^|[;}\s\n])\s*)export\s*\{([^}]+)\}\s*;?/g,(function(e,n,r){return u(r,!0),n})).replace(/((?:^|[^a-zA-Z0-9$_@`'".])\s*)(import\s*\([\s\S]+?\))/g,"$1$$$2")).replace(/((?:^|[^a-zA-Z0-9$_@`'".])\s*)import\.meta\.url/g,"$1"+JSON.stringify(s))+"\n$module.exports={"+t.join(",")+"}"}(e,f),Promise.all(f.map((function(e){var s=r(o,e);return s in n?n[s]:t(s)}))).then((function(n){e+="\n//# sourceURL="+s;try{var r=new Function("$import","$require","$module","$exports",e)}catch(n){var t=n.line-1,a=n.column,o=e.split("\n"),p=(o[t-2]||"")+"\n"+o[t-1]+"\n"+(null==a?"":new Array(a).join("-")+"^\n")+(o[t]||""),l=new Error(n.message+"\n\n"+p,s,t);throw l.sourceURL=l.fileName=s,l.line=t,l.column=a,l}var m=r(i,(function(e){return n[f.indexOf(e)]}),c,c.exports);return null!=m&&(c.exports=m),Object.assign(u,c.exports),c.exports}))}))})))}(a).then((function(){removeEventListener("message",s),t.map(dispatchEvent)})).catch((function(e){setTimeout((function(){throw e}))}))}()}}(self.Worker); - } -} \ No newline at end of file diff --git a/frontend/src/environments/environment.block_producers.ts b/frontend/src/environments/environment.block_producers.ts index 2c6fea236d..8f9a1f4dfe 100644 --- a/frontend/src/environments/environment.block_producers.ts +++ b/frontend/src/environments/environment.block_producers.ts @@ -10,6 +10,7 @@ export const environment: Readonly = { 'snarks': ['scan-state', 'work-pool'], }, canAddNodes: true, + graphQL: 'http://localhost:11010/graphql', }, configs: [ { diff --git a/frontend/src/environments/environment.compose.ts b/frontend/src/environments/environment.compose.ts index 94f85fb5ca..c3daac10e4 100644 --- a/frontend/src/environments/environment.compose.ts +++ b/frontend/src/environments/environment.compose.ts @@ -10,6 +10,7 @@ export const environment: Readonly = { state: ['actions'], network: ['node-dht', 'graph-overview', 'bootstrap-stats'], snarks: ['scan-state'], + benchmarks: ['wallets'], }, canAddNodes: true, }, diff --git a/frontend/src/environments/environment.staging.ts b/frontend/src/environments/environment.staging.ts deleted file mode 100644 index aff951d38d..0000000000 --- a/frontend/src/environments/environment.staging.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { MinaEnv } from '@shared/types/core/environment/mina-env.type'; - -export const environment: Readonly = { - production: true, - globalConfig: { - features: { - 'dashboard': [], - 'block-production': ['won-slots'], - 'nodes': ['overview', 'live', 'bootstrap'], - 'mempool': [], - 'state': ['actions'], - 'snarks': ['scan-state', 'work-pool'], - 'benchmarks': ['wallets'], - }, - canAddNodes: false, - }, - configs: [ - { - name: 'staging-devnet-bp-0', - url: 'https://staging-devnet-openmina-bp-0.minaprotocol.network', - }, - { - name: 'staging-devnet-bp-1', - url: 'https://staging-devnet-openmina-bp-1.minaprotocol.network', - }, - { - name: 'staging-devnet-bp-2', - url: 'https://staging-devnet-openmina-bp-2.minaprotocol.network', - }, - { - name: 'staging-devnet-bp-3', - url: 'https://staging-devnet-openmina-bp-3.minaprotocol.network', - }, - ], -}; - diff --git a/frontend/src/environments/environment.ts b/frontend/src/environments/environment.ts index e9dca000cf..1aa4df76b7 100644 --- a/frontend/src/environments/environment.ts +++ b/frontend/src/environments/environment.ts @@ -3,6 +3,7 @@ import { MinaEnv } from '@shared/types/core/environment/mina-env.type'; export const environment: Readonly = { production: false, identifier: 'Dev FE', + webNodeKey: '', globalConfig: { features: { dashboard: [], @@ -12,13 +13,15 @@ export const environment: Readonly = { snarks: ['scan-state', 'work-pool'], 'testing-tool': ['scenarios'], resources: ['memory'], - 'block-production': ['overview', 'won-slots'], + 'block-production': ['won-slots'], mempool: [], benchmarks: ['wallets'], zk: ['test'], }, canAddNodes: true, - graphQL: 'http://adonagy.hz.minaprotocol.network:3000/graphql', + graphQL: 'https://adonagy.com/graphql', + // graphQL: 'https://api.minascan.io/node/devnet/v1/graphql', + // graphQL: 'http://65.109.105.40:5000/graphql', }, configs: [ // { @@ -53,10 +56,10 @@ export const environment: Readonly = { name: 'staging-devnet-bp-3', url: 'https://staging-devnet-openmina-bp-3.minaprotocol.network', }, - // { - // name: 'Web Node 1', - // isWebNode: true, - // }, + { + name: 'Web Node 1', + isWebNode: true, + }, // { // name: 'http://65.109.105.40:3000', // url: 'http://65.109.105.40:3000', diff --git a/frontend/src/index.html b/frontend/src/index.html index 7389a55234..26abb901d1 100644 --- a/frontend/src/index.html +++ b/frontend/src/index.html @@ -29,15 +29,17 @@ diff --git a/frontend/webpack.config.js b/frontend/webpack.config.js index bb5701b2ae..02f8b7391b 100644 --- a/frontend/webpack.config.js +++ b/frontend/webpack.config.js @@ -1,25 +1,5 @@ -const TerserPlugin = require("terser-webpack-plugin"); -console.log('Loading custom webpack!') module.exports = { experiments: { topLevelAwait: true, }, - optimization: { - minimize: true, - minimizer: [ - new TerserPlugin({ - terserOptions: { - ecma: undefined, - parse: {}, - compress: { - keep_classnames: true, - keep_fargs: true, - keep_fnames: true, - }, - keep_classnames: true, - keep_fnames: true, - }, - }), - ], - } } diff --git a/fuzzer/Cargo.toml b/fuzzer/Cargo.toml index 305ec2637c..f34008228a 100644 --- a/fuzzer/Cargo.toml +++ b/fuzzer/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openmina-fuzzer" -version = "0.9.0" +version = "0.10.0" edition = "2021" license = "Apache-2.0" diff --git a/ledger/Cargo.toml b/ledger/Cargo.toml index f2de40d929..1097cc8ee3 100644 --- a/ledger/Cargo.toml +++ b/ledger/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mina-tree" -version = "0.9.0" +version = "0.10.0" edition = "2021" license = "Apache-2.0" @@ -26,7 +26,10 @@ o1-utils = { workspace = true } kimchi = { workspace = true } mina-poseidon = { workspace = true } poly-commitment = { workspace = true } +juniper = { workspace = true } openmina-macros = { path = "../macros" } +strum = "0.26.2" +strum_macros = "0.26.4" bs58 = "0.4.0" mina-p2p-messages = { workspace = true } diff --git a/ledger/src/account/account.rs b/ledger/src/account/account.rs index 79e8c6ea0d..b5dbe4e1c3 100644 --- a/ledger/src/account/account.rs +++ b/ledger/src/account/account.rs @@ -419,6 +419,12 @@ pub struct VerificationKey { pub wrap_vk: Option<()>, } +// impl From for MinaBaseVerificationKeyWireStableV1Base64 { +// fn from(value: VerificationKey) -> Self { +// MinaBaseVerificationKeyWireStableV1Base64((&value).into()) +// } +// } + impl Check for VerificationKey { fn check(&self, w: &mut Witness) { let Self { @@ -884,6 +890,10 @@ impl ZkAppAccount { pub fn empty_action_state() -> Fp { cache_one!(Fp, { hash_noinputs("MinaZkappActionStateEmptyElt") }) } + + pub fn is_default(&self) -> bool { + self == &Self::default() + } } /// An `AccountId` implementing `Ord` & `PartialOrd`, reproducing OCaml ordering. diff --git a/ledger/src/account/common.rs b/ledger/src/account/common.rs index 3bbe65d6ee..d7cd4fb913 100644 --- a/ledger/src/account/common.rs +++ b/ledger/src/account/common.rs @@ -41,6 +41,13 @@ impl VotingFor { let state_hash = mina_p2p_messages::v2::StateHash::from_fp(self.0); state_hash.to_string() } + + pub fn to_base58check_graphql(&self) -> String { + // NOTE: See https://github.com/MinaProtocol/mina/blob/fb1c3c0a408c344810140bdbcedacc532a11be91/src/lib/mina_graphql/types.ml#L1528 + let receipt_chain_hash = ReceiptChainHash(self.0); + let receipt_chain_hash = mina_p2p_messages::v2::ReceiptChainHash::from(receipt_chain_hash); + receipt_chain_hash.to_string() + } } #[test] @@ -241,7 +248,7 @@ impl Default for TokenPermissions { } // https://github.com/MinaProtocol/mina/blob/develop/src/lib/mina_base/permissions.mli#L10 -#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, strum_macros::Display)] #[serde(rename_all = "lowercase")] pub enum AuthRequired { None, diff --git a/ledger/src/account/conv.rs b/ledger/src/account/conv.rs index 17103fad53..8e0a3fab14 100644 --- a/ledger/src/account/conv.rs +++ b/ledger/src/account/conv.rs @@ -1,7 +1,7 @@ #![allow(clippy::type_complexity)] use ark_ec::short_weierstrass_jacobian::GroupAffine; -use ark_ff::{fields::arithmetic::InvalidBigInt, Field}; +use ark_ff::{fields::arithmetic::InvalidBigInt, Field, PrimeField}; use mina_hasher::Fp; use mina_p2p_messages::{ bigint::BigInt, @@ -11,8 +11,9 @@ use mina_p2p_messages::{ self, MinaBaseAccountBinableArgStableV2, MinaBaseAccountIdDigestStableV1, MinaBaseAccountIdStableV2, MinaBaseAccountIndexStableV1, MinaBaseAccountTimingStableV2, MinaBasePermissionsAuthRequiredStableV2, MinaBasePermissionsStableV2, - MinaBaseVerificationKeyWireStableV1, MinaBaseVerificationKeyWireStableV1WrapIndex, - NonZeroCurvePointUncompressedStableV1, PicklesBaseProofsVerifiedStableV1, TokenIdKeyHash, + MinaBaseReceiptChainHashStableV1, MinaBaseVerificationKeyWireStableV1, + MinaBaseVerificationKeyWireStableV1WrapIndex, NonZeroCurvePointUncompressedStableV1, + PicklesBaseProofsVerifiedStableV1, TokenIdKeyHash, }, }; @@ -56,6 +57,12 @@ impl From for TokenIdKeyHash { } } +impl From for TokenId { + fn from(value: TokenIdKeyHash) -> Self { + value.inner().try_into().unwrap() + } +} + impl TryFrom<(BigInt, BigInt)> for InnerCurve where F: Field + From, @@ -642,6 +649,12 @@ impl From for MinaBaseAccountIndexStableV1 { } } +impl From for mina_p2p_messages::v2::ReceiptChainHash { + fn from(value: ReceiptChainHash) -> Self { + MinaBaseReceiptChainHashStableV1(value.0.into_repr().into()).into() + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/ledger/src/generators/zkapp_command.rs b/ledger/src/generators/zkapp_command.rs index b007106644..11f3b03895 100644 --- a/ledger/src/generators/zkapp_command.rs +++ b/ledger/src/generators/zkapp_command.rs @@ -33,7 +33,10 @@ use crate::{ }, Memo, }, - zkapp_logic::{self, ZkAppCommandElt}, + }, + zkapps::{ + non_snark::ZkappNonSnark, + zkapp_logic::{update_action_state, ZkAppCommandElt}, }, Account, AccountId, AuthRequired, BaseLedger, ControlTag, Mask, MutableFp, MyCowMut, Permissions, ReceiptChainHash, SetVerificationKey, TokenId, VerificationKeyWire, VotingFor, @@ -907,11 +910,12 @@ fn gen_account_update_body_components( Some(ps) => ps.global_slot_since_genesis, }; - let (action_state, _last_action_slot) = zkapp_logic::update_action_state( - zk.action_state, - actions.clone(), + let (action_state, _last_action_slot) = update_action_state::>( + &zk.action_state, + &actions, txn_global_slot, last_action_slot, + &mut (), ); action_state diff --git a/ledger/src/proofs/accumulator_check.rs b/ledger/src/proofs/accumulator_check.rs index 782697c1c3..c40908b6a0 100644 --- a/ledger/src/proofs/accumulator_check.rs +++ b/ledger/src/proofs/accumulator_check.rs @@ -9,38 +9,52 @@ use super::urs_utils; pub fn accumulator_check( urs: &SRS, - proof: &PicklesProofProofsVerified2ReprStableV2, + proofs: &[&PicklesProofProofsVerified2ReprStableV2], ) -> Result { // accumulator check + // https://github.com/MinaProtocol/mina/blob/fb1c3c0a408c344810140bdbcedacc532a11be91/src/lib/pickles/common.ml#L191-L204 // Note: // comms: statement.proof_state.messages_for_next_wrap_proof.challenge_polynomial_commitment + // Array.of_list_map comm_chals ~f:(fun (comm, _) -> Or_infinity.Finite comm ) // chals: statement.proof_state.deferred_values.bulletproof_challenges + // Array.concat @@ List.map comm_chals ~f:(fun (_, chals) -> Vector.to_array chals) - let deferred_values = &proof.statement.proof_state.deferred_values; - let bulletproof_challenges = &deferred_values.bulletproof_challenges; - let bulletproof_challenges: Vec = bulletproof_challenges - .iter() - .map(|chal| { - let prechallenge = &chal.prechallenge.inner; - let prechallenge: [u64; 2] = prechallenge.each_ref().map(|c| c.as_u64()); - - ScalarChallenge::limbs_to_field(&prechallenge) - }) - .collect(); - - let of_coord = - |(x, y): &(BigInt, BigInt)| Ok(Vesta::of_coordinates(x.to_field()?, y.to_field()?)); - - // statement.proof_state.messages_for_next_wrap_proof.challenge_polynomial_commitment - let acc_comm = &proof - .statement - .proof_state - .messages_for_next_wrap_proof - .challenge_polynomial_commitment; - let acc_comm: Vesta = of_coord(acc_comm)?; - - let acc_check = - urs_utils::batch_dlog_accumulator_check(urs, &[acc_comm], &bulletproof_challenges); + let mut comms = Vec::with_capacity(proofs.len()); + let mut bulletproof_challenges = vec![]; + + for proof in proofs { + let chals = &proof + .statement + .proof_state + .deferred_values + .bulletproof_challenges; + let mut chals: Vec = chals + .iter() + .map(|chal| { + let prechallenge = &chal.prechallenge.inner; + let prechallenge: [u64; 2] = prechallenge.each_ref().map(|c| c.as_u64()); + + ScalarChallenge::limbs_to_field(&prechallenge) + }) + .collect(); + + bulletproof_challenges.append(&mut chals); + + let of_coord = + |(x, y): &(BigInt, BigInt)| Ok(Vesta::of_coordinates(x.to_field()?, y.to_field()?)); + + // statement.proof_state.messages_for_next_wrap_proof.challenge_polynomial_commitment + let acc_comm = &proof + .statement + .proof_state + .messages_for_next_wrap_proof + .challenge_polynomial_commitment; + let acc_comm: Vesta = of_coord(acc_comm)?; + + comms.push(acc_comm); + } + + let acc_check = urs_utils::batch_dlog_accumulator_check(urs, &comms, &bulletproof_challenges); if !acc_check { println!("accumulator_check failed"); diff --git a/ledger/src/proofs/step.rs b/ledger/src/proofs/step.rs index 88033a8327..0ab038072f 100644 --- a/ledger/src/proofs/step.rs +++ b/ledger/src/proofs/step.rs @@ -8,7 +8,7 @@ use crate::{ prepared_statement::{DeferredValues, PreparedStatement, ProofState}, }, unfinalized::dummy_ipa_step_challenges_computed, - util::proof_evaluation_to_list, + util::proof_evaluation_to_absorption_sequence, verifiers::wrap_domains, wrap::{ create_oracle_with_public_input, dummy_ipa_wrap_sg, wrap_verifier, Domain, @@ -2002,7 +2002,7 @@ pub fn expand_deferred(params: ExpandDeferredParams) -> Result = old_bulletproof_challenges diff --git a/ledger/src/proofs/transaction.rs b/ledger/src/proofs/transaction.rs index 0247a4ddfa..2ba60c89b4 100644 --- a/ledger/src/proofs/transaction.rs +++ b/ledger/src/proofs/transaction.rs @@ -4181,7 +4181,7 @@ mod tests_with_wasm { } #[cfg(test)] -mod tests { +pub(super) mod tests { use std::path::Path; use mina_p2p_messages::binprot::{ @@ -4215,7 +4215,7 @@ mod tests { PerformJob(mina_p2p_messages::v2::SnarkWorkerWorkerRpcsVersionedGetWorkV2TResponse), } - fn panic_in_ci() { + pub fn panic_in_ci() { fn is_ci() -> bool { std::env::var("CI").is_ok() } @@ -4633,7 +4633,7 @@ mod tests { } #[test] - fn test_zkapp_proof_sig() { + fn test_proof_zkapp_sig() { let Ok(data) = std::fs::read( Path::new(env!("CARGO_MANIFEST_DIR")) .join(devnet_circuit_directory()) diff --git a/ledger/src/proofs/util.rs b/ledger/src/proofs/util.rs index 8f094a1ddb..e41613a40c 100644 --- a/ledger/src/proofs/util.rs +++ b/ledger/src/proofs/util.rs @@ -134,7 +134,7 @@ pub fn challenge_polynomial_checked( } /// Note: Outdated URL -/// Note: Same as `to_absorption_sequence` +/// Note: Different than `to_absorption_sequence` /// https://github.com/MinaProtocol/mina/blob/4af0c229548bc96d76678f11b6842999de5d3b0b/src/lib/pickles_types/plonk_types.ml#L611 pub fn proof_evaluation_to_list( e: &ProofEvaluations>>, @@ -211,6 +211,86 @@ pub fn proof_evaluation_to_list( list } +pub fn proof_evaluation_to_absorption_sequence( + e: &ProofEvaluations>>, +) -> Vec<&PointEvaluations>> { + let ProofEvaluations { + public: _, + w, + coefficients, + z, + s, + generic_selector, + poseidon_selector, + complete_add_selector, + mul_selector, + emul_selector, + endomul_scalar_selector, + range_check0_selector, + range_check1_selector, + foreign_field_add_selector, + foreign_field_mul_selector, + xor_selector, + rot_selector, + lookup_aggregation, + lookup_table, + lookup_sorted, + runtime_lookup_table, + runtime_lookup_table_selector, + xor_lookup_selector, + lookup_gate_lookup_selector, + range_check_lookup_selector, + foreign_field_mul_lookup_selector, + } = e; + + let mut list = vec![ + z, + generic_selector, + poseidon_selector, + complete_add_selector, + mul_selector, + emul_selector, + endomul_scalar_selector, + ]; + + list.extend(w.iter()); + list.extend(coefficients.iter()); + list.extend(s.iter()); + + list.extend( + [ + range_check0_selector, + range_check1_selector, + foreign_field_add_selector, + foreign_field_mul_selector, + xor_selector, + rot_selector, + lookup_aggregation, + lookup_table, + ] + .into_iter() + .filter_map(|v| v.as_ref()), + ); + + list.extend(lookup_sorted.iter().filter_map(|v| v.as_ref())); + + list.extend( + [ + runtime_lookup_table, + runtime_lookup_table_selector, + xor_lookup_selector, + lookup_gate_lookup_selector, + range_check_lookup_selector, + foreign_field_mul_lookup_selector, + ] + .into_iter() + .filter_map(|v| v.as_ref()), + ); + + #[allow(clippy::iter_cloned_collect)] + list.iter().cloned().collect() +} + /// https://github.com/MinaProtocol/mina/blob/4af0c229548bc96d76678f11b6842999de5d3b0b/src/lib/pickles_types/plonk_types.ml#L611 pub fn proof_evaluation_to_list_opt( e: &ProofEvaluations>>, @@ -312,7 +392,98 @@ pub fn to_absorption_sequence_opt( evals: &ProofEvaluations>>, hack_feature_flags: OptFlag, ) -> Vec>>> { - proof_evaluation_to_list_opt(evals, hack_feature_flags) + let ProofEvaluations { + public: _, + w, + coefficients, + z, + s, + generic_selector, + poseidon_selector, + complete_add_selector, + mul_selector, + emul_selector, + endomul_scalar_selector, + range_check0_selector, + range_check1_selector, + foreign_field_add_selector, + foreign_field_mul_selector, + xor_selector, + rot_selector, + lookup_aggregation, + lookup_table, + lookup_sorted, + runtime_lookup_table, + runtime_lookup_table_selector, + xor_lookup_selector, + lookup_gate_lookup_selector, + range_check_lookup_selector, + foreign_field_mul_lookup_selector, + } = evals; + + let mut list = vec![ + Opt::Some(z.clone()), + Opt::Some(generic_selector.clone()), + Opt::Some(poseidon_selector.clone()), + Opt::Some(complete_add_selector.clone()), + Opt::Some(mul_selector.clone()), + Opt::Some(emul_selector.clone()), + Opt::Some(endomul_scalar_selector.clone()), + ]; + + list.extend(w.iter().cloned().map(Opt::Some)); + list.extend(coefficients.iter().cloned().map(Opt::Some)); + list.extend(s.iter().cloned().map(Opt::Some)); + + let zero = || PointEvaluations { + zeta: vec![F::zero()], + zeta_omega: vec![F::zero()], + }; + let to_opt = |v: &Option>>| { + if let OptFlag::Maybe = hack_feature_flags { + match v { + Some(v) => Opt::Maybe(Boolean::True, v.clone()), + None => Opt::Maybe(Boolean::False, zero()), + } + } else { + match v { + Some(v) => Opt::Some(v.clone()), + None => Opt::No, + } + } + }; + + list.extend( + [ + range_check0_selector, + range_check1_selector, + foreign_field_add_selector, + foreign_field_mul_selector, + xor_selector, + rot_selector, + lookup_aggregation, + lookup_table, + ] + .iter() + .map(|e| to_opt(e)), + ); + + list.extend(lookup_sorted.iter().map(to_opt)); + + list.extend( + [ + runtime_lookup_table, + runtime_lookup_table_selector, + xor_lookup_selector, + lookup_gate_lookup_selector, + range_check_lookup_selector, + foreign_field_mul_lookup_selector, + ] + .into_iter() + .map(to_opt), + ); + + list } pub fn sha256_sum(s: &[u8]) -> String { diff --git a/ledger/src/proofs/verification.rs b/ledger/src/proofs/verification.rs index 69779070a8..cf23f67216 100644 --- a/ledger/src/proofs/verification.rs +++ b/ledger/src/proofs/verification.rs @@ -3,6 +3,7 @@ use std::rc::Rc; use ark_ff::fields::arithmetic::InvalidBigInt; use ark_poly::{EvaluationDomain, Radix2EvaluationDomain}; use ark_serialize::Write; +use itertools::Itertools; use poly_commitment::srs::SRS; use crate::{ @@ -519,6 +520,38 @@ fn verify_with( ) } +pub struct VerificationContext<'a> { + pub verifier_index: &'a VerifierIndex, + pub proof: &'a ProverProof, + pub public_input: &'a [Fq], +} + +fn batch_verify(proofs: &[VerificationContext]) -> Result<(), VerifyError> { + use kimchi::groupmap::GroupMap; + use kimchi::mina_curves::pasta::PallasParameters; + use kimchi::verifier::Context; + use mina_poseidon::sponge::{DefaultFqSponge, DefaultFrSponge}; + use poly_commitment::evaluation_proof::OpeningProof; + + type SpongeParams = mina_poseidon::constants::PlonkSpongeConstantsKimchi; + type EFqSponge = DefaultFqSponge; + type EFrSponge = DefaultFrSponge; + + let group_map = GroupMap::::setup(); + let proofs = proofs + .iter() + .map(|p| Context { + verifier_index: p.verifier_index, + proof: p.proof, + public_input: p.public_input, + }) + .collect_vec(); + + kimchi::verifier::batch_verify::>( + &group_map, &proofs, + ) +} + fn run_checks( proof: &PicklesProofProofsVerified2ReprStableV2, verifier_index: &VerifierIndex, @@ -713,7 +746,7 @@ pub fn verify_block( let protocol_state_hash = MinaHash::hash(&protocol_state); let accum_check = - accumulator_check::accumulator_check(srs, protocol_state_proof).unwrap_or(false); + accumulator_check::accumulator_check(srs, &[protocol_state_proof]).unwrap_or(false); let verified = verify_impl(&protocol_state_hash, protocol_state_proof, &vk).unwrap_or(false); accum_check && verified @@ -730,12 +763,27 @@ pub fn verify_transaction<'a>( data: (), }; - proofs.into_iter().all(|(statement, transaction_proof)| { - let accum_check = - accumulator_check::accumulator_check(srs, transaction_proof).unwrap_or(false); - let verified = verify_impl(statement, transaction_proof, &vk).unwrap_or(false); - accum_check && verified - }) + let mut inputs: Vec<( + &Statement, + &PicklesProofProofsVerified2ReprStableV2, + &VK, + )> = Vec::with_capacity(128); + + let mut accum_check_proofs: Vec<&PicklesProofProofsVerified2ReprStableV2> = + Vec::with_capacity(128); + + proofs + .into_iter() + .for_each(|(statement, transaction_proof)| { + accum_check_proofs.push(transaction_proof); + inputs.push((statement, transaction_proof, &vk)); + }); + + let accum_check = + accumulator_check::accumulator_check(srs, &accum_check_proofs).unwrap_or(false); + + let verified = batch_verify_impl(inputs.as_slice()).unwrap_or(false); + accum_check && verified } /// https://github.com/MinaProtocol/mina/blob/bfd1009abdbee78979ff0343cc73a3480e862f58/src/lib/crypto/kimchi_bindings/stubs/src/pasta_fq_plonk_proof.rs#L116 @@ -753,13 +801,15 @@ pub fn verify_zkapp( data: (), }; - let accum_check = accumulator_check::accumulator_check(srs, sideloaded_proof).unwrap_or(false); + let accum_check = + accumulator_check::accumulator_check(srs, &[sideloaded_proof]).unwrap_or(false); let verified = verify_impl(&zkapp_statement, sideloaded_proof, &vk).unwrap_or(false); let ok = accum_check && verified; eprintln!("verify_zkapp OK={:?}", ok); + #[cfg(not(test))] if !ok { if let Err(e) = dump_zkapp_verification(verification_key, zkapp_statement, sideloaded_proof) { @@ -810,6 +860,57 @@ where Ok(result.is_ok() && checks) } +fn batch_verify_impl( + proofs: &[(&AppState, &PicklesProofProofsVerified2ReprStableV2, &VK)], +) -> Result +where + AppState: ToFieldElements, +{ + let mut verification_contexts = Vec::with_capacity(proofs.len()); + let mut checks = true; + + for (app_state, proof, vk) in proofs { + let deferred_values = compute_deferred_values(proof)?; + checks = checks && run_checks(proof, vk.index); + + let message_for_next_step_proof = get_message_for_next_step_proof( + &proof.statement.messages_for_next_step_proof, + &vk.commitments, + app_state, + )?; + + let message_for_next_wrap_proof = get_message_for_next_wrap_proof( + &proof.statement.proof_state.messages_for_next_wrap_proof, + )?; + + let prepared_statement = get_prepared_statement( + &message_for_next_step_proof, + &message_for_next_wrap_proof, + deferred_values, + &proof.statement.proof_state.sponge_digest_before_evaluations, + ); + + let npublic_input = vk.index.public; + let public_inputs = prepared_statement.to_public_input(npublic_input)?; + let proof_padded = make_padded_proof_from_p2p(proof)?; + + verification_contexts.push((vk.index, proof_padded, public_inputs)); + } + + let proofs: Vec = verification_contexts + .iter() + .map(|(vk, proof, public_input)| VerificationContext { + verifier_index: vk, + proof, + public_input, + }) + .collect(); + + let result = batch_verify(&proofs); + + Ok(result.is_ok() && checks) +} + /// Dump data when it fails, to reproduce and compare in OCaml fn dump_zkapp_verification( verification_key: &VerificationKey, @@ -866,110 +967,145 @@ fn generate_new_filename(name: &str, extension: &str, data: &[u8]) -> std::io::R Err(std::io::Error::other("no filename available")) } -// #[cfg(test)] -// mod tests { -// use std::{ -// collections::hash_map::DefaultHasher, -// hash::{Hash, Hasher}, -// }; - -// // use binprot::BinProtRead; -// use mina_curves::pasta::{Vesta, Fq}; -// use mina_hasher::Fp; -// use mina_p2p_messages::v2::MinaBlockHeaderStableV2; -// use poly_commitment::srs::SRS; - -// use crate::{ -// proofs::{caching::{ -// srs_from_bytes, srs_to_bytes, verifier_index_from_bytes, verifier_index_to_bytes, -// }, verifier_index::{get_verifier_index, VerifierKind}}, verifier::get_srs, -// // get_srs, get_verifier_index, -// }; - -// #[cfg(target_family = "wasm")] -// use wasm_bindgen_test::wasm_bindgen_test as test; - -// #[test] -// fn test_verification() { -// let now = redux::Instant::now(); -// let verifier_index = get_verifier_index(VerifierKind::Blockchain); -// println!("get_verifier_index={:?}", now.elapsed()); - -// let now = redux::Instant::now(); -// let srs = get_srs::(); -// let srs = srs.lock().unwrap(); -// println!("get_srs={:?}\n", now.elapsed()); - -// // let now = redux::Instant::now(); -// // let bytes = verifier_index_to_bytes(&verifier_index); -// // println!("verifier_elapsed={:?}", now.elapsed()); -// // println!("verifier_length={:?}", bytes.len()); -// // assert_eq!(bytes.len(), 5622520); - -// // let now = redux::Instant::now(); -// // let verifier_index = verifier_index_from_bytes(&bytes); -// // println!("verifier_deserialize_elapsed={:?}\n", now.elapsed()); - -// // let now = redux::Instant::now(); -// // let bytes = srs_to_bytes(&srs); -// // println!("srs_elapsed={:?}", now.elapsed()); -// // println!("srs_length={:?}", bytes.len()); -// // assert_eq!(bytes.len(), 5308513); - -// // let now = redux::Instant::now(); -// // let srs: SRS = srs_from_bytes(&bytes); -// // println!("deserialize_elapsed={:?}\n", now.elapsed()); - -// // Few blocks headers from berkeleynet -// let files = [ -// include_bytes!("/tmp/block-rampup4.binprot"), -// // include_bytes!("../data/5573.binprot"), -// // include_bytes!("../data/5574.binprot"), -// // include_bytes!("../data/5575.binprot"), -// // include_bytes!("../data/5576.binprot"), -// // include_bytes!("../data/5577.binprot"), -// // include_bytes!("../data/5578.binprot"), -// // include_bytes!("../data/5579.binprot"), -// // include_bytes!("../data/5580.binprot"), -// ]; - -// use mina_p2p_messages::binprot::BinProtRead; -// use crate::proofs::accumulator_check::accumulator_check; - -// for file in files { -// let header = MinaBlockHeaderStableV2::binprot_read(&mut file.as_slice()).unwrap(); - -// let now = redux::Instant::now(); -// let accum_check = accumulator_check(&*srs, &header.protocol_state_proof.0); -// println!("accumulator_check={:?}", now.elapsed()); - -// let now = redux::Instant::now(); -// let verified = super::verify_block(&header, &verifier_index, &*srs); - -// // let verified = crate::verify(&header, &verifier_index); -// println!("snark::verify={:?}", now.elapsed()); - -// assert!(accum_check); -// assert!(verified); -// } -// } - -// #[test] -// fn test_verifier_index_deterministic() { -// let mut nruns = 0; -// let nruns = &mut nruns; - -// let mut hash_verifier_index = || { -// *nruns += 1; -// let verifier_index = get_verifier_index(); -// let bytes = verifier_index_to_bytes(&verifier_index); - -// let mut hasher = DefaultHasher::new(); -// bytes.hash(&mut hasher); -// hasher.finish() -// }; - -// assert_eq!(hash_verifier_index(), hash_verifier_index()); -// assert_eq!(*nruns, 2); -// } -// } +#[cfg(test)] +mod tests { + use std::path::Path; + + use mina_hasher::Fp; + use mina_p2p_messages::{binprot::BinProtRead, v2}; + + use crate::proofs::{provers::devnet_circuit_directory, transaction::tests::panic_in_ci}; + + use super::*; + + #[cfg(target_family = "wasm")] + use wasm_bindgen_test::wasm_bindgen_test as test; + + #[test] + fn test_verify_zkapp() { + use mina_p2p_messages::binprot; + use mina_p2p_messages::binprot::macros::{BinProtRead, BinProtWrite}; + + #[derive(Clone, Debug, PartialEq, BinProtRead, BinProtWrite)] + struct VerifyZkapp { + vk: v2::MinaBaseVerificationKeyWireStableV1, + zkapp_statement: v2::MinaBaseZkappStatementStableV2, + proof: v2::PicklesProofProofsVerified2ReprStableV2, + } + + let base_dir = Path::new(env!("CARGO_MANIFEST_DIR")) + .join(devnet_circuit_directory()) + .join("tests"); + + let cases = [ + "verify_zapp_4af39d1e141859c964fe32b4e80537d3bd8c32d75e2754c0b869738006d25251_0.binprot", + "verify_zapp_dc518dc7e0859ea6ffa0cd42637cdcc9c79ab369dfb7ff44c8a89b1219f98728_0.binprot", + "verify_zapp_9db7255327f342f75d27b5c0f646988ee68c6338f6e26c4dc549675f811b4152_0.binprot", + "verify_zapp_f2bbc8088654c09314a58c96428f6828d3ee8096b6f34e3a027ad9b028ae22e0_0.binprot", + ]; + + for filename in cases { + let Ok(file) = std::fs::read(base_dir.join(filename)) else { + panic_in_ci(); + return; + }; + + let VerifyZkapp { + vk, + zkapp_statement, + proof, + } = VerifyZkapp::binprot_read(&mut file.as_slice()).unwrap(); + + let vk = (&vk).try_into().unwrap(); + let zkapp_statement = (&zkapp_statement).try_into().unwrap(); + let srs = crate::verifier::get_srs::(); + + let ok = verify_zkapp(&vk, &zkapp_statement, &proof, &srs); + assert!(ok); + } + } + + // #[test] + // fn test_verification() { + // let now = redux::Instant::now(); + // let verifier_index = get_verifier_index(VerifierKind::Blockchain); + // println!("get_verifier_index={:?}", now.elapsed()); + + // let now = redux::Instant::now(); + // let srs = get_srs::(); + // let srs = srs.lock().unwrap(); + // println!("get_srs={:?}\n", now.elapsed()); + + // // let now = redux::Instant::now(); + // // let bytes = verifier_index_to_bytes(&verifier_index); + // // println!("verifier_elapsed={:?}", now.elapsed()); + // // println!("verifier_length={:?}", bytes.len()); + // // assert_eq!(bytes.len(), 5622520); + + // // let now = redux::Instant::now(); + // // let verifier_index = verifier_index_from_bytes(&bytes); + // // println!("verifier_deserialize_elapsed={:?}\n", now.elapsed()); + + // // let now = redux::Instant::now(); + // // let bytes = srs_to_bytes(&srs); + // // println!("srs_elapsed={:?}", now.elapsed()); + // // println!("srs_length={:?}", bytes.len()); + // // assert_eq!(bytes.len(), 5308513); + + // // let now = redux::Instant::now(); + // // let srs: SRS = srs_from_bytes(&bytes); + // // println!("deserialize_elapsed={:?}\n", now.elapsed()); + + // // Few blocks headers from berkeleynet + // let files = [ + // include_bytes!("/tmp/block-rampup4.binprot"), + // // include_bytes!("../data/5573.binprot"), + // // include_bytes!("../data/5574.binprot"), + // // include_bytes!("../data/5575.binprot"), + // // include_bytes!("../data/5576.binprot"), + // // include_bytes!("../data/5577.binprot"), + // // include_bytes!("../data/5578.binprot"), + // // include_bytes!("../data/5579.binprot"), + // // include_bytes!("../data/5580.binprot"), + // ]; + + // use mina_p2p_messages::binprot::BinProtRead; + // use crate::proofs::accumulator_check::accumulator_check; + + // for file in files { + // let header = MinaBlockHeaderStableV2::binprot_read(&mut file.as_slice()).unwrap(); + + // let now = redux::Instant::now(); + // let accum_check = accumulator_check(&*srs, &header.protocol_state_proof.0); + // println!("accumulator_check={:?}", now.elapsed()); + + // let now = redux::Instant::now(); + // let verified = super::verify_block(&header, &verifier_index, &*srs); + + // // let verified = crate::verify(&header, &verifier_index); + // println!("snark::verify={:?}", now.elapsed()); + + // assert!(accum_check); + // assert!(verified); + // } + // } + + // #[test] + // fn test_verifier_index_deterministic() { + // let mut nruns = 0; + // let nruns = &mut nruns; + + // let mut hash_verifier_index = || { + // *nruns += 1; + // let verifier_index = get_verifier_index(); + // let bytes = verifier_index_to_bytes(&verifier_index); + + // let mut hasher = DefaultHasher::new(); + // bytes.hash(&mut hasher); + // hasher.finish() + // }; + + // assert_eq!(hash_verifier_index(), hash_verifier_index()); + // assert_eq!(*nruns, 2); + // } +} diff --git a/ledger/src/proofs/zkapp.rs b/ledger/src/proofs/zkapp.rs index 7eb8e03638..a66891a986 100644 --- a/ledger/src/proofs/zkapp.rs +++ b/ledger/src/proofs/zkapp.rs @@ -488,10 +488,12 @@ pub fn zkapp_command_witnesses_exn( zkapp_command, } = v; - let (txn_applied, states) = { - let (partial_txn, states) = first_pass_ledger + let mut states = Vec::with_capacity(16); + let txn_applied = { + let partial_txn = first_pass_ledger .clone() .apply_zkapp_first_pass_unchecked_with_states( + &mut states, global_slot, &state_view, fee_excess, @@ -503,7 +505,7 @@ pub fn zkapp_command_witnesses_exn( second_pass_ledger .clone() - .apply_zkapp_second_pass_unchecked_with_states(states, partial_txn) + .apply_zkapp_second_pass_unchecked_with_states(&mut states, partial_txn) .unwrap() }; @@ -745,8 +747,8 @@ pub fn zkapp_command_witnesses_exn( data: call_stack, hash: Fp::zero(), // TODO }, - transaction_commitment: TransactionCommitment(transaction_commitment.0), - full_transaction_commitment: TransactionCommitment(full_transaction_commitment.0), + transaction_commitment: TransactionCommitment(transaction_commitment), + full_transaction_commitment: TransactionCommitment(full_transaction_commitment), excess, supply_increase, ledger, diff --git a/ledger/src/scan_state/mod.rs b/ledger/src/scan_state/mod.rs index ad2e968f30..bc98982c43 100644 --- a/ledger/src/scan_state/mod.rs +++ b/ledger/src/scan_state/mod.rs @@ -9,7 +9,6 @@ pub mod protocol_state; pub mod scan_state; pub mod snark_work; pub mod transaction_logic; -pub mod zkapp_logic; pub use parallel_scan::SpacePartition; pub struct GenesisConstant { diff --git a/ledger/src/scan_state/scan_state.rs b/ledger/src/scan_state/scan_state.rs index f892df1631..e41c041749 100644 --- a/ledger/src/scan_state/scan_state.rs +++ b/ledger/src/scan_state/scan_state.rs @@ -35,9 +35,10 @@ use crate::{ TransactionStatus, }, }, - sparse_ledger::{LedgerIntf, SparseLedger}, + sparse_ledger::SparseLedger, staged_ledger::hash::AuxHash, verifier::Verifier, + zkapps::non_snark::LedgerNonSnark, }; use self::transaction_snark::{InitStack, LedgerProof, OneOrTwo, Registers}; @@ -1434,7 +1435,7 @@ impl ScanState { apply_first_pass_sparse_ledger: ApplyFirstSparse, ) -> Result where - L: LedgerIntf + Clone, + L: LedgerNonSnark, F: Fn(Fp) -> Result, ApplyFirst: Fn( Slot, @@ -1455,7 +1456,7 @@ impl ScanState { let stop_at_first_pass = stop_at_first_pass.unwrap_or(false); #[derive(Clone)] - enum PreviousIncompleteTxns { + enum PreviousIncompleteTxns { Unapplied(Vec>), PartiallyApplied(Vec<(TransactionStatus, TransactionPartiallyApplied)>), } @@ -1469,7 +1470,7 @@ impl ScanState { get_protocol_state: F, ) -> Result, String> where - L: LedgerIntf + Clone, + L: LedgerNonSnark, F: Fn(Fp) -> Result, Apply: Fn( Slot, @@ -1536,7 +1537,7 @@ impl ScanState { apply_second_pass: ApplySecond, ) -> Result<(), String> where - L: LedgerIntf + Clone, + L: LedgerNonSnark, ApplySecond: Fn(&mut L, TransactionPartiallyApplied) -> Result, { @@ -1568,7 +1569,7 @@ impl ScanState { apply_txns_second_pass: ApplySecondPass, ) -> Result where - L: LedgerIntf + Clone, + L: LedgerNonSnark, F: Fn(Fp) -> Result, ApplySecondPass: Fn(Acc) -> Result, ApplyFirstSparse: Fn( @@ -1622,7 +1623,7 @@ impl ScanState { block_global_slot: zkapp.global_state.block_global_slot, }; - let local_state = LocalStateEnv { + let local_state = LocalStateEnv:: { stack_frame: zkapp.local_state.stack_frame, call_stack: zkapp.local_state.call_stack, transaction_commitment: zkapp.local_state.transaction_commitment, @@ -1711,7 +1712,7 @@ impl ScanState { apply_txns_second_pass: &'a impl Fn(Acc) -> Result<(), String>, ) -> Result where - L: LedgerIntf + Clone + 'a, + L: LedgerNonSnark, { use PreviousIncompleteTxns::{PartiallyApplied, Unapplied}; @@ -1862,7 +1863,7 @@ impl ScanState { apply_first_pass_sparse_ledger: ApplyFirstSparse, ) -> Result where - L: LedgerIntf + Clone, + L: LedgerNonSnark, F: Fn(Fp) -> Result, ApplyFirst: Fn( Slot, @@ -1899,7 +1900,7 @@ impl ScanState { apply_first_pass_sparse_ledger: ApplyFirstSparse, ) -> Result where - L: LedgerIntf + Clone, + L: LedgerNonSnark, F: Fn(Fp) -> Result, ApplyFirst: Fn( Slot, @@ -1939,7 +1940,7 @@ impl ScanState { apply_first_pass_sparse_ledger: ApplyFirstSparse, ) -> Result where - L: LedgerIntf + Clone, + L: LedgerNonSnark, F: Fn(Fp) -> Result, ApplyFirst: Fn( Slot, diff --git a/ledger/src/scan_state/transaction_logic.rs b/ledger/src/scan_state/transaction_logic.rs index 54b50588d3..81e863defe 100644 --- a/ledger/src/scan_state/transaction_logic.rs +++ b/ledger/src/scan_state/transaction_logic.rs @@ -14,9 +14,10 @@ use openmina_macros::SerdeYojsonEnum; use crate::proofs::witness::Witness; use crate::scan_state::transaction_logic::transaction_partially_applied::FullyApplied; use crate::scan_state::transaction_logic::zkapp_command::MaybeWithStatus; -use crate::scan_state::zkapp_logic; +use crate::zkapps::non_snark::{LedgerNonSnark, ZkappNonSnark}; use crate::{ - hash_with_kimchi, AccountIdOrderable, BaseLedger, ControlTag, Inputs, VerificationKeyWire, + hash_with_kimchi, zkapps, AccountIdOrderable, BaseLedger, ControlTag, Inputs, + VerificationKeyWire, }; use crate::{ scan_state::transaction_logic::transaction_applied::{CommandApplied, Varying}, @@ -24,7 +25,7 @@ use crate::{ Account, AccountId, ReceiptChainHash, Timing, TokenId, }; -use self::zkapp_command::{AccessedOrNot, Numeric}; +use self::zkapp_command::AccessedOrNot; use self::{ local_state::{CallStack, LocalStateEnv, StackFrame}, protocol_state::{GlobalState, ProtocolStateView}, @@ -34,18 +35,17 @@ use self::{ TransactionApplied, ZkappCommandApplied, }, transaction_union_payload::TransactionUnionPayload, - zkapp_command::{AccountUpdate, WithHash, ZkAppCommand, ZkAppPreconditions}, + zkapp_command::{AccountUpdate, WithHash, ZkAppCommand}, }; use super::currency::SlotSpan; use super::fee_rate::FeeRate; -use super::zkapp_logic::ZkAppCommandElt; use super::{ currency::{Amount, Balance, Fee, Index, Length, Magnitude, Nonce, Signed, Slot}, fee_excess::FeeExcess, scan_state::transaction_snark::OneOrTwo, - zkapp_logic::{Handler, StartData}, }; +use crate::zkapps::zkapp_logic::ZkAppCommandElt; /// https://github.com/MinaProtocol/mina/blob/2ee6e004ba8c6a0541056076aab22ea162f7eb3a/src/lib/mina_base/transaction_status.ml#L9 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] @@ -561,9 +561,9 @@ impl std::str::FromStr for Memo { fn from_str(s: &str) -> Result { let length = std::cmp::min(s.len(), Self::DIGEST_LENGTH) as u8; - let mut memo: [u8; Self::DIGEST_LENGTH + 2] = std::array::from_fn(|i| (i == 0) as u8); - memo[0] = Self::BYTES_TAG; - memo[1] = length; + let mut memo: [u8; Self::MEMO_LENGTH] = std::array::from_fn(|i| (i == 0) as u8); + memo[Self::TAG_INDEX] = Self::BYTES_TAG; + memo[Self::LENGTH_INDEX] = length; let padded = format!("{s:\0<32}"); memo[2..].copy_from_slice( &padded.as_bytes()[..std::cmp::min(padded.len(), Self::DIGEST_LENGTH)], @@ -926,7 +926,7 @@ pub mod zkapp_command { use rand::{seq::SliceRandom, Rng}; use crate::{ - account, dummy, gen_compressed, gen_keypair, hash_noinputs, + dummy, gen_compressed, gen_keypair, hash_noinputs, proofs::{ field::{Boolean, ToBoolean}, to_field_elements::ToFieldElements, @@ -936,7 +936,7 @@ pub mod zkapp_command { currency::{MinMax, Sgn}, GenesisConstant, GENESIS_CONSTANT, }, - zkapps::snark::zkapp_check::InSnarkCheck, + zkapps::checks::{ZkappCheck, ZkappCheckOps}, AuthRequired, MutableFp, MyCow, Permissions, SetVerificationKey, ToInputs, TokenSymbol, VerificationKey, VerificationKeyWire, VotingFor, ZkAppAccount, ZkAppUri, }; @@ -1536,31 +1536,6 @@ pub mod zkapp_command { } } - pub trait OutSnarkCheck { - type A; - type B; - - /// zkapp check - fn zcheck(&self, label: String, x: Self::B) -> Result<(), String>; - } - - impl OutSnarkCheck for T - where - T: Eq, - { - type A = T; - type B = T; - - /// zkapp check - fn zcheck(&self, label: String, rhs: Self::B) -> Result<(), String> { - if *self == rhs { - Ok(()) - } else { - Err(format!("Equality check failed: {}", label)) - } - } - } - // TODO: This could be std::ops::Range ? /// https://github.com/MinaProtocol/mina/blob/2ee6e004ba8c6a0541056076aab22ea162f7eb3a/src/lib/mina_base/zkapp_precondition.ml#L23 #[derive(Debug, Clone, PartialEq)] @@ -1617,27 +1592,6 @@ pub mod zkapp_command { } } - impl OutSnarkCheck for ClosedInterval - where - T: PartialOrd + std::fmt::Debug, - { - type A = ClosedInterval; - type B = T; - - /// zkapp check - fn zcheck(&self, label: String, rhs: Self::B) -> Result<(), String> { - /*println!( - "bounds check lower {:?} rhs {:?} upper {:?}", - self.lower, rhs, self.upper - );*/ - if self.lower <= rhs && rhs <= self.upper { - Ok(()) - } else { - Err(format!("Bounds check failed: {}", label)) - } - } - } - impl ClosedInterval where T: PartialOrd, @@ -1735,20 +1689,6 @@ pub mod zkapp_command { } } - impl OrIgnore - where - T: OutSnarkCheck, - { - /// zkapp check - pub fn zcheck(&self, label: String, rhs: T::B) -> Result<(), String> { - // println!("[rust] check {}, {:?}", label, ret); - match self { - Self::Ignore => Ok(()), - Self::Check(t) => t.zcheck(label, rhs), - } - } - } - impl OrIgnore { /// https://github.com/MinaProtocol/mina/blob/d7d4aa4d650eb34b45a42b29276554802683ce15/src/lib/mina_base/zkapp_basic.ml#L239 pub fn gen(mut fun: F) -> Self @@ -1804,14 +1744,6 @@ pub mod zkapp_command { pub total_currency: Numeric, } - impl EpochLedger { - pub fn epoch_ledger(&self, t: protocol_state::EpochLedger) -> Result<(), String> { - self.hash.zcheck("epoch_ledger_hash".to_string(), t.hash)?; - self.total_currency - .zcheck("epoch_ledger_total_currency".to_string(), t.total_currency) - } - } - /// https://github.com/MinaProtocol/mina/blob/2ee6e004ba8c6a0541056076aab22ea162f7eb3a/src/lib/mina_base/zkapp_precondition.ml#L797 #[derive(Debug, Clone, PartialEq)] pub struct EpochData { @@ -1905,25 +1837,6 @@ pub mod zkapp_command { } impl EpochData { - pub fn epoch_data( - &self, - label: &str, - t: protocol_state::EpochData, - ) -> Result<(), String> { - self.ledger.epoch_ledger(t.ledger)?; - // ignore seed - self.start_checkpoint.zcheck( - format!("{}_{}", label, "start_checkpoint"), - t.start_checkpoint, - )?; - self.lock_checkpoint.zcheck( - format!("{}_{}", label, "lock_checkpoint"), - t.lock_checkpoint, - )?; - self.epoch_length - .zcheck(format!("{}_{}", label, "epoch_length"), t.epoch_length) - } - pub fn gen() -> Self { let mut rng = rand::thread_rng(); @@ -1953,27 +1866,11 @@ pub mod zkapp_command { } impl ZkAppPreconditions { - /// zkapp check - pub fn zcheck(&self, s: ProtocolStateView) -> Result<(), String> { - self.snarked_ledger_hash - .zcheck("snarker_ledger_hash".to_string(), s.snarked_ledger_hash)?; - self.blockchain_length - .zcheck("blockchain_length".to_string(), s.blockchain_length)?; - self.min_window_density - .zcheck("min_window_density".to_string(), s.min_window_density)?; - self.total_currency - .zcheck("total_currency".to_string(), s.total_currency)?; - self.global_slot_since_genesis.zcheck( - "global_slot_since_genesis".to_string(), - s.global_slot_since_genesis, - )?; - self.staking_epoch_data - .epoch_data("staking_epoch_data", s.staking_epoch_data)?; - self.next_epoch_data - .epoch_data("next_epoch_data", s.next_epoch_data) - } - - pub fn checked_zcheck(&self, s: &ProtocolStateView, w: &mut Witness) -> Boolean { + pub fn zcheck( + &self, + s: &ProtocolStateView, + w: &mut Witness, + ) -> Boolean { let Self { snarked_ledger_hash, blockchain_length, @@ -2000,40 +1897,38 @@ pub mod zkapp_command { lock_checkpoint, epoch_length, } = epoch_data; - // Reverse to match OCaml order of the list, while still executing `checked_zcheck` + // Reverse to match OCaml order of the list, while still executing `zcheck` // in correct order [ - (epoch_length, ClosedInterval::min_max).checked_zcheck(&view.epoch_length, w), - (lock_checkpoint, Fp::zero).checked_zcheck(&view.lock_checkpoint, w), - (start_checkpoint, Fp::zero).checked_zcheck(&view.start_checkpoint, w), + (epoch_length, ClosedInterval::min_max).zcheck::(&view.epoch_length, w), + (lock_checkpoint, Fp::zero).zcheck::(&view.lock_checkpoint, w), + (start_checkpoint, Fp::zero).zcheck::(&view.start_checkpoint, w), (total_currency, ClosedInterval::min_max) - .checked_zcheck(&view.ledger.total_currency, w), - (hash, Fp::zero).checked_zcheck(&view.ledger.hash, w), + .zcheck::(&view.ledger.total_currency, w), + (hash, Fp::zero).zcheck::(&view.ledger.hash, w), ] }; let next_epoch_data = epoch_data(next_epoch_data, &s.next_epoch_data, w); let staking_epoch_data = epoch_data(staking_epoch_data, &s.staking_epoch_data, w); - // Reverse to match OCaml order of the list, while still executing `checked_zcheck` + // Reverse to match OCaml order of the list, while still executing `zcheck` // in correct order let bools = [ (global_slot_since_genesis, ClosedInterval::min_max) - .checked_zcheck(&s.global_slot_since_genesis, w), - (total_currency, ClosedInterval::min_max).checked_zcheck(&s.total_currency, w), + .zcheck::(&s.global_slot_since_genesis, w), + (total_currency, ClosedInterval::min_max).zcheck::(&s.total_currency, w), (min_window_density, ClosedInterval::min_max) - .checked_zcheck(&s.min_window_density, w), - (blockchain_length, ClosedInterval::min_max) - .checked_zcheck(&s.blockchain_length, w), - (snarked_ledger_hash, Fp::zero).checked_zcheck(&s.snarked_ledger_hash, w), + .zcheck::(&s.min_window_density, w), + (blockchain_length, ClosedInterval::min_max).zcheck::(&s.blockchain_length, w), + (snarked_ledger_hash, Fp::zero).zcheck::(&s.snarked_ledger_hash, w), ] .into_iter() .rev() .chain(staking_epoch_data.into_iter().rev()) - .chain(next_epoch_data.into_iter().rev()) - .collect::>(); + .chain(next_epoch_data.into_iter().rev()); - Boolean::all(&bools, w) + Ops::boolean_all(bools, w) } /// https://github.com/MinaProtocol/mina/blob/3753a8593cc1577bcf4da16620daf9946d88e8e5/src/lib/mina_base/zkapp_precondition.ml#L1303 @@ -2166,80 +2061,7 @@ pub mod zkapp_command { } impl Account { - /// zkapp check - pub fn zcheck(&self, new_account: bool, mut check: F, a: account::Account) - where - F: FnMut(TransactionFailure, bool), - { - self.zchecks(new_account, a) - .iter() - .for_each(|(failure, res)| check(failure.clone(), res.is_ok())) - } - - fn zchecks( - &self, - new_account: bool, - a: account::Account, - ) -> Vec<(TransactionFailure, Result<(), String>)> { - let zkapp = a.zkapp.unwrap_or_default(); - let mut ret = vec![ - ( - TransactionFailure::AccountBalancePreconditionUnsatisfied, - self.balance.zcheck("balance".to_string(), a.balance), - ), - ( - TransactionFailure::AccountNoncePreconditionUnsatisfied, - self.nonce.zcheck("nonce".to_string(), a.nonce), - ), - ( - TransactionFailure::AccountReceiptChainHashPreconditionUnsatisfied, - self.receipt_chain_hash - .zcheck("receipt_chain_hash".to_string(), a.receipt_chain_hash.0), - ), - ( - TransactionFailure::AccountDelegatePreconditionUnsatisfied, - self.delegate.zcheck( - "delegate".to_string(), - a.delegate.unwrap_or_else(invalid_public_key), - ), - ), - ( - TransactionFailure::AccountActionStatePreconditionUnsatisfied, - match zkapp - .action_state - .iter() - .find(|state| self.action_state.zcheck("".to_string(), **state).is_ok()) - { - None => Err("Action state mismatch".to_string()), - Some(_) => Ok(()), - }, - ), - ]; - - for (i, (c, v)) in self.state.iter().zip(zkapp.app_state.iter()).enumerate() { - ret.push(( - TransactionFailure::AccountAppStatePreconditionUnsatisfied(i as u64), - c.zcheck(format!("state[{}]", i), *v), - )); - } - - let mut ret2 = vec![ - ( - TransactionFailure::AccountProvedStatePreconditionUnsatisfied, - self.proved_state - .zcheck("proved_state".to_string(), zkapp.proved_state), - ), - ( - TransactionFailure::AccountIsNewPreconditionUnsatisfied, - self.is_new.zcheck("is_new".to_string(), new_account), - ), - ]; - - ret.append(&mut ret2); - ret - } - - fn checked_zchecks( + fn zchecks( &self, account: &crate::Account, new_account: Boolean, @@ -2262,7 +2084,7 @@ pub mod zkapp_command { let is_new = is_new.map(ToBoolean::to_boolean); let proved_state = proved_state.map(ToBoolean::to_boolean); - // NOTE: Here we need to execute all `checked_zcheck` in the exact same order than OCaml + // NOTE: Here we need to execute all `zcheck` in the exact same order than OCaml // so we execute them in reverse order (compared to OCaml): OCaml evaluates from right // to left. // We then have to reverse the resulting vector, to match OCaml resulting list. @@ -2271,12 +2093,12 @@ pub mod zkapp_command { let mut checks: Vec<(TransactionFailure, _)> = [ ( AccountIsNewPreconditionUnsatisfied, - (&is_new, || Boolean::False).checked_zcheck(&new_account, w), + (&is_new, || Boolean::False).zcheck::(&new_account, w), ), ( AccountProvedStatePreconditionUnsatisfied, (&proved_state, || Boolean::False) - .checked_zcheck(&zkapp_account.proved_state.to_boolean(), w), + .zcheck::(&zkapp_account.proved_state.to_boolean(), w), ), ] .into_iter() @@ -2287,7 +2109,7 @@ pub mod zkapp_command { .enumerate() .rev() .map(|(i, (s, account_s))| { - let b = (s, Fp::zero).checked_zcheck(account_s, w); + let b = (s, Fp::zero).zcheck::(account_s, w); (AccountAppStatePreconditionUnsatisfied(i as u64), b) }) .collect::>(); @@ -2301,30 +2123,30 @@ pub mod zkapp_command { .iter() .map(|account_s| { (action_state, ZkAppAccount::empty_action_state) - .checked_zcheck(account_s, w) + .zcheck::(account_s, w) }) .collect(); ( AccountActionStatePreconditionUnsatisfied, - Boolean::any(&bools, w), + Ops::boolean_any(bools, w), ) }, ( AccountDelegatePreconditionUnsatisfied, (delegate, CompressedPubKey::empty) - .checked_zcheck(&*account.delegate_or_empty(), w), + .zcheck::(&*account.delegate_or_empty(), w), ), ( AccountReceiptChainHashPreconditionUnsatisfied, - (receipt_chain_hash, Fp::zero).checked_zcheck(&account.receipt_chain_hash.0, w), + (receipt_chain_hash, Fp::zero).zcheck::(&account.receipt_chain_hash.0, w), ), ( AccountNoncePreconditionUnsatisfied, - (nonce, ClosedInterval::min_max).checked_zcheck(&account.nonce, w), + (nonce, ClosedInterval::min_max).zcheck::(&account.nonce, w), ), ( AccountBalancePreconditionUnsatisfied, - (balance, ClosedInterval::min_max).checked_zcheck(&account.balance, w), + (balance, ClosedInterval::min_max).zcheck::(&account.balance, w), ), ]) .collect::>(); @@ -2446,17 +2268,18 @@ pub mod zkapp_command { MyCow::Borrow(&self.0) } - pub fn checked_zcheck( + pub fn zcheck( &self, new_account: Boolean, account: &crate::Account, mut check: Fun, w: &mut Witness, ) where + Ops: ZkappCheckOps, Fun: FnMut(TransactionFailure, Boolean, &mut Witness), { let this = self.to_full(); - for (failure, passed) in this.checked_zchecks(account, new_account, w) { + for (failure, passed) in this.zchecks::(account, new_account, w) { check(failure, passed, w); } } @@ -5227,7 +5050,7 @@ pub mod protocol_state { } #[must_use] - fn set_fee_excess(&self, fee_excess: Signed) -> Self { + pub fn set_fee_excess(&self, fee_excess: Signed) -> Self { let mut this = self.clone(); this.fee_excess = fee_excess; this @@ -5244,7 +5067,7 @@ pub mod protocol_state { this } - fn block_global_slot(&self) -> Slot { + pub fn block_global_slot(&self) -> Slot { self.block_global_slot } } @@ -5569,17 +5392,20 @@ pub mod local_state { /// One with concrete types for the stack frame, call stack, and ledger. Created from the Env /// And the other with their hashes. To differentiate them I renamed the first LocalStateEnv /// Maybe a better solution is to keep the LocalState name and put it under a different module - pub type LocalStateEnv = LocalStateSkeleton< - L, // ledger - StackFrame, // stack_frame - CallStack, // call_stack - ReceiptChainHash, // commitments - Signed, // excess & supply_increase - Vec>, // failure_status_tbl - bool, // success & will_succeed - Index, // account_update_index - >; - + // pub type LocalStateEnv = LocalStateSkeleton< + // L, // ledger + // StackFrame, // stack_frame + // CallStack, // call_stack + // ReceiptChainHash, // commitments + // Signed, // excess & supply_increase + // Vec>, // failure_status_tbl + // bool, // success & will_succeed + // Index, // account_update_index + // >; + + pub type LocalStateEnv = crate::zkapps::zkapp_logic::LocalState>; + + // TODO: Dedub this with `crate::zkapps::zkapp_logic::LocalState` #[derive(Debug, Clone)] pub struct LocalStateSkeleton< L: LedgerIntf + Clone, @@ -5605,32 +5431,35 @@ pub mod local_state { pub will_succeed: Bool, } - impl LocalStateEnv { - pub fn add_new_failure_status_bucket(&self) -> Self { - let mut failure_status_tbl = self.failure_status_tbl.clone(); - failure_status_tbl.insert(0, Vec::new()); - Self { - failure_status_tbl, - ..self.clone() - } - } - - pub fn add_check(&self, failure: TransactionFailure, b: bool) -> Self { - let failure_status_tbl = if !b { - let mut failure_status_tbl = self.failure_status_tbl.clone(); - failure_status_tbl[0].insert(0, failure); - failure_status_tbl - } else { - self.failure_status_tbl.clone() - }; - - Self { - failure_status_tbl, - success: self.success && b, - ..self.clone() - } - } - } + // impl LocalStateEnv + // where + // L: LedgerNonSnark, + // { + // pub fn add_new_failure_status_bucket(&self) -> Self { + // let mut failure_status_tbl = self.failure_status_tbl.clone(); + // failure_status_tbl.insert(0, Vec::new()); + // Self { + // failure_status_tbl, + // ..self.clone() + // } + // } + + // pub fn add_check(&self, failure: TransactionFailure, b: bool) -> Self { + // let failure_status_tbl = if !b { + // let mut failure_status_tbl = self.failure_status_tbl.clone(); + // failure_status_tbl[0].insert(0, failure); + // failure_status_tbl + // } else { + // self.failure_status_tbl.clone() + // }; + + // Self { + // failure_status_tbl, + // success: self.success && b, + // ..self.clone() + // } + // } + // } #[derive(Debug, Clone, PartialEq, Eq)] pub struct LocalState { @@ -5785,156 +5614,20 @@ pub mod local_state { } } -// let equal' (t1 : t) (t2 : t) = -// let ( ! ) f x y = Impl.run_checked (f x y) in -// let f eq acc f = Core_kernel.Field.(eq (get f t1) (get f t2)) :: acc in -// Mina_transaction_logic.Zkapp_command_logic.Local_state.Fields.fold ~init:[] -// ~stack_frame:(f Stack_frame.Digest.Checked.equal) -// ~call_stack:(f Call_stack_digest.Checked.equal) -// ~transaction_commitment:(f Field.equal) -// ~full_transaction_commitment:(f Field.equal) -// ~excess:(f !Currency.Amount.Signed.Checked.equal) -// ~supply_increase:(f !Currency.Amount.Signed.Checked.equal) -// ~ledger:(f !Ledger_hash.equal_var) ~success:(f Impl.Boolean.equal) -// ~account_update_index:(f !Mina_numbers.Index.Checked.equal) -// ~failure_status_tbl:(f (fun () () -> Impl.Boolean.true_)) -// ~will_succeed:(f Impl.Boolean.equal) - -pub enum Eff { - CheckValidWhilePrecondition(Numeric, GlobalState), - CheckAccountPrecondition(AccountUpdate, Account, bool, LocalStateEnv), - CheckProtocolStatePrecondition(Box, GlobalState), - InitAccount(AccountUpdate, Account), -} - -pub struct Env { - account_update: AccountUpdate, - zkapp_command: ZkAppCommand, - account: Account, - ledger: L, - amount: Amount, - signed_amount: Signed, - bool: bool, - token_id: TokenId, - global_state: GlobalState, - local_state: LocalStateEnv, - protocol_state_precondition: ZkAppPreconditions, - valid_while_precondition: Numeric, - transaction_commitment: Fp, - full_transaction_commitment: Fp, - field: Fp, - failure: Option, -} - -pub enum PerformResult { - Bool(bool), - LocalState(Box>), - Account(Box), -} - -impl PerformResult { - pub fn to_bool(self) -> bool { - match self { - PerformResult::Bool(v) => v, - _ => panic!("Not a bool"), - } - } -} - -impl Env -where - L: LedgerIntf + Clone, -{ - pub fn perform(eff: Eff) -> PerformResult { - match eff { - Eff::CheckValidWhilePrecondition(valid_while, global_state) => PerformResult::Bool( - valid_while - .zcheck( - "valid_while_precondition".to_string(), - global_state.block_global_slot, - ) - .is_ok(), - ), - Eff::CheckProtocolStatePrecondition(pred, global_state) => { - PerformResult::Bool(pred.zcheck(global_state.protocol_state).is_ok()) - } - Eff::CheckAccountPrecondition(account_update, account, new_account, local_state) => { - let local_state = { - let precondition_account = &account_update.body.preconditions.account.0; - let mut _local_state = local_state; - let check = |failure, b| { - _local_state = _local_state.add_check(failure, b); - }; - precondition_account.zcheck(new_account, check, account); - _local_state - }; - PerformResult::LocalState(Box::new(local_state)) - } - Eff::InitAccount(_account_update, a) => PerformResult::Account(Box::new(a)), - } - } -} - -// fn step_all( -// constraint_constants: &ConstraintConstants, -// f: &impl Fn( -// Option<(LocalStateEnv, Signed)>, -// (GlobalState, LocalStateEnv), -// ) -> Option<(LocalStateEnv, Signed)>, -// h: fn(Eff) -> PerformResult, -// user_acc: Option<(LocalStateEnv, Signed)>, -// (g_state, l_state): (GlobalState, LocalStateEnv), -// ) -> Result< -// ( -// Option<(LocalStateEnv, Signed)>, -// Vec>, -// ), -// String, -// > -// where -// L: LedgerIntf + Clone, -// { -// if l_state.stack_frame.calls.is_empty() { -// Ok((user_acc, l_state.failure_status_tbl)) -// } else { -// let states = apply( -// constraint_constants, -// IsStart::No, -// Handler { perform: h }, -// (g_state, l_state), -// ); -// step_all( -// constraint_constants, -// f, -// h, -// f(user_acc, states.clone()), -// states, -// ) -// } -// } - fn step_all( - constraint_constants: &ConstraintConstants, - f: &impl Fn(A, (GlobalState, LocalStateEnv)) -> A, - handler: &Handler, - user_acc: A, - (g_state, l_state): (GlobalState, LocalStateEnv), -) -> Result<(A, Vec>), String> + _constraint_constants: &ConstraintConstants, + f: &impl Fn(&mut A, &GlobalState, &LocalStateEnv), + user_acc: &mut A, + (g_state, l_state): (&mut GlobalState, &mut LocalStateEnv), +) -> Result>, String> where - L: LedgerIntf + Clone, + L: LedgerNonSnark, { - if l_state.stack_frame.calls.is_empty() { - Ok((user_acc, l_state.failure_status_tbl)) - } else { - let states = zkapp_logic::step(constraint_constants, handler, (g_state, l_state))?; - step_all( - constraint_constants, - f, - handler, - f(user_acc, states.clone()), - states, - ) + while !l_state.stack_frame.calls.is_empty() { + zkapps::non_snark::step(g_state, l_state)?; + f(user_acc, g_state, l_state); } + Ok(l_state.failure_status_tbl.clone()) } /// apply zkapp command fee payer's while stubbing out the second pass ledger @@ -5944,16 +5637,16 @@ pub fn apply_zkapp_command_first_pass_aux( constraint_constants: &ConstraintConstants, global_slot: Slot, state_view: &ProtocolStateView, - init: A, + init: &mut A, f: F, fee_excess: Option>, supply_increase: Option>, ledger: &mut L, command: &ZkAppCommand, -) -> Result<(ZkappCommandPartiallyApplied, A), String> +) -> Result, String> where - L: LedgerIntf + Clone, - F: Fn(A, (GlobalState, LocalStateEnv)) -> A, + L: LedgerNonSnark, + F: Fn(&mut A, &GlobalState, &LocalStateEnv), { let fee_excess = fee_excess.unwrap_or_else(Signed::zero); let supply_increase = supply_increase.unwrap_or_else(Signed::zero); @@ -5969,17 +5662,16 @@ where vec![(id, location)] }; + // let perform = |eff: Eff| Env::perform(eff); - let perform = |eff: Eff| Env::perform(eff); - - let initial_state = ( + let (mut global_state, mut local_state) = ( GlobalState { protocol_state: state_view.clone(), first_pass_ledger: ledger.clone(), second_pass_ledger: { // We stub out the second_pass_ledger initially, and then poke the // correct value in place after the first pass is finished. - L::empty(0) + ::empty(0) }, fee_excess, supply_increase, @@ -5988,11 +5680,11 @@ where LocalStateEnv { stack_frame: StackFrame::default(), call_stack: CallStack::new(), - transaction_commitment: ReceiptChainHash(Fp::zero()), - full_transaction_commitment: ReceiptChainHash(Fp::zero()), + transaction_commitment: Fp::zero(), + full_transaction_commitment: Fp::zero(), excess: Signed::::zero(), supply_increase, - ledger: L::empty(0), + ledger: ::empty(0), success: true, account_update_index: Index::zero(), failure_status_tbl: Vec::new(), @@ -6000,23 +5692,20 @@ where }, ); - let user_acc = f(init, initial_state.clone()); + f(init, &global_state, &local_state); let account_updates = command.all_account_updates(); - let (global_state, local_state) = { - zkapp_logic::start( - constraint_constants, - StartData { - account_updates, - memo_hash: command.memo.hash(), - // It's always valid to set this value to true, and it will - // have no effect outside of the snark. - will_succeed: true, - }, - &Handler { perform }, - initial_state, - )? - }; + zkapps::non_snark::start( + &mut global_state, + &mut local_state, + zkapps::non_snark::StartData { + account_updates, + memo_hash: command.memo.hash(), + // It's always valid to set this value to true, and it will + // have no effect outside of the snark. + will_succeed: true, + }, + )?; let command = command.clone(); let constraint_constants = constraint_constants.clone(); @@ -6032,7 +5721,7 @@ where local_state, }; - Ok((res, user_acc)) + Ok(res) } fn apply_zkapp_command_first_pass( @@ -6045,14 +5734,15 @@ fn apply_zkapp_command_first_pass( command: &ZkAppCommand, ) -> Result, String> where - L: LedgerIntf + Clone, + L: LedgerNonSnark, { - let (partial_stmt, _user_acc) = apply_zkapp_command_first_pass_aux( + let mut acc = (); + let partial_stmt = apply_zkapp_command_first_pass_aux( constraint_constants, global_slot, state_view, - None, - |_acc, state| Some(state), + &mut acc, + |_acc, _g, _l| {}, fee_excess, supply_increase, ledger, @@ -6064,16 +5754,16 @@ where pub fn apply_zkapp_command_second_pass_aux( constraint_constants: &ConstraintConstants, - init: A, + init: &mut A, f: F, ledger: &mut L, c: ZkappCommandPartiallyApplied, -) -> Result<(ZkappCommandApplied, A), String> +) -> Result where - L: LedgerIntf + Clone, - F: Fn(A, (GlobalState, LocalStateEnv)) -> A, + L: LedgerNonSnark, + F: Fn(&mut A, &GlobalState, &LocalStateEnv), { - let perform = |eff: Eff| Env::perform(eff); + // let perform = |eff: Eff| Env::perform(eff); let original_account_states: Vec<(AccountId, Option<_>)> = { // get the original states of all the accounts in each pass. @@ -6142,12 +5832,12 @@ where // TODO(OCaml): Remove this, and uplift the logic into the call in staged ledger. - let global_state = GlobalState { + let mut global_state = GlobalState { second_pass_ledger: ledger.clone(), ..c.global_state }; - let local_state = { + let mut local_state = { if c.local_state.stack_frame.calls.is_empty() { // Don't mess with the local state; we've already finished the // transaction after the fee payer. @@ -6162,15 +5852,10 @@ where } }; - let start = (global_state, local_state); + f(init, &global_state, &local_state); + let start = (&mut global_state, &mut local_state); - let (user_acc, reversed_failure_status_tbl) = step_all( - constraint_constants, - &f, - &Handler { perform }, - f(init, start.clone()), - start, - )?; + let reversed_failure_status_tbl = step_all(constraint_constants, &f, init, start)?; let failure_status_tbl = reversed_failure_status_tbl .into_iter() @@ -6217,21 +5902,18 @@ where let new_accounts_is_empty = new_accounts.is_empty(); - let valid_result = Ok(( - ZkappCommandApplied { - accounts: accounts(), - command: WithStatus { - data: c.command, - status: if successfully_applied { - TransactionStatus::Applied - } else { - TransactionStatus::Failed(failure_status_tbl) - }, + let valid_result = Ok(ZkappCommandApplied { + accounts: accounts(), + command: WithStatus { + data: c.command, + status: if successfully_applied { + TransactionStatus::Applied + } else { + TransactionStatus::Failed(failure_status_tbl) }, - new_accounts, }, - user_acc, - )); + new_accounts, + }); if successfully_applied { valid_result @@ -6261,10 +5943,15 @@ fn apply_zkapp_command_second_pass( c: ZkappCommandPartiallyApplied, ) -> Result where - L: LedgerIntf + Clone, + L: LedgerNonSnark, { - let (x, _) = - apply_zkapp_command_second_pass_aux(constraint_constants, (), |a, _| a, ledger, c)?; + let x = apply_zkapp_command_second_pass_aux( + constraint_constants, + &mut (), + |_, _, _| {}, + ledger, + c, + )?; Ok(x) } @@ -6272,18 +5959,18 @@ fn apply_zkapp_command_unchecked_aux( constraint_constants: &ConstraintConstants, global_slot: Slot, state_view: &ProtocolStateView, - init: A, + init: &mut A, f: F, fee_excess: Option>, supply_increase: Option>, ledger: &mut L, command: &ZkAppCommand, -) -> Result<(ZkappCommandApplied, A), String> +) -> Result where - L: LedgerIntf + Clone, - F: Fn(A, (GlobalState, LocalStateEnv)) -> A, + L: LedgerNonSnark, + F: Fn(&mut A, &GlobalState, &LocalStateEnv), { - let (partial_stmt, user_acc) = apply_zkapp_command_first_pass_aux( + let partial_stmt = apply_zkapp_command_first_pass_aux( constraint_constants, global_slot, state_view, @@ -6295,7 +5982,7 @@ where command, )?; - apply_zkapp_command_second_pass_aux(constraint_constants, user_acc, f, ledger, partial_stmt) + apply_zkapp_command_second_pass_aux(constraint_constants, init, &f, ledger, partial_stmt) } fn apply_zkapp_command_unchecked( @@ -6306,7 +5993,7 @@ fn apply_zkapp_command_unchecked( command: &ZkAppCommand, ) -> Result<(ZkappCommandApplied, (LocalStateEnv, Signed)), String> where - L: LedgerIntf + Clone, + L: LedgerNonSnark, { let zkapp_partially_applied: ZkappCommandPartiallyApplied = apply_zkapp_command_first_pass( constraint_constants, @@ -6318,15 +6005,19 @@ where command, )?; - let (account_update_applied, state_res) = apply_zkapp_command_second_pass_aux( + let mut state_res = None; + let account_update_applied = apply_zkapp_command_second_pass_aux( constraint_constants, - None, - |_acc, (global_state, local_state)| Some((local_state, global_state.fee_excess)), + &mut state_res, + |acc, global_state, local_state| { + *acc = Some((local_state.clone(), global_state.fee_excess)) + }, ledger, zkapp_partially_applied, )?; + let (state, amount) = state_res.unwrap(); - Ok((account_update_applied, state_res.unwrap())) + Ok((account_update_applied, (state.clone(), amount))) } pub mod transaction_partially_applied { @@ -6336,7 +6027,7 @@ pub mod transaction_partially_applied { }; #[derive(Clone, Debug)] - pub struct ZkappCommandPartiallyApplied { + pub struct ZkappCommandPartiallyApplied { pub command: ZkAppCommand, pub previous_hash: Fp, pub original_first_pass_account_states: @@ -6354,14 +6045,17 @@ pub mod transaction_partially_applied { } #[derive(Clone, Debug)] - pub enum TransactionPartiallyApplied { + pub enum TransactionPartiallyApplied { SignedCommand(FullyApplied), ZkappCommand(Box>), FeeTransfer(FullyApplied), Coinbase(FullyApplied), } - impl TransactionPartiallyApplied { + impl TransactionPartiallyApplied + where + L: LedgerNonSnark, + { pub fn command(self) -> Transaction { use Transaction as T; @@ -6387,7 +6081,7 @@ pub fn apply_transaction_first_pass( transaction: &Transaction, ) -> Result, String> where - L: LedgerIntf + Clone, + L: LedgerNonSnark, { use Transaction::*; use UserCommand::*; @@ -6447,7 +6141,7 @@ pub fn apply_transaction_second_pass( partial_transaction: TransactionPartiallyApplied, ) -> Result where - L: LedgerIntf + Clone, + L: LedgerNonSnark, { use TransactionPartiallyApplied as P; @@ -6498,7 +6192,7 @@ pub fn apply_transactions( txns: &[Transaction], ) -> Result, String> where - L: LedgerIntf + Clone, + L: LedgerNonSnark, { let first_pass: Vec<_> = txns .iter() @@ -7895,7 +7589,7 @@ pub fn validate_timing( pub fn account_check_timing( txn_global_slot: &Slot, account: &Account, -) -> (TimingValidation, Timing) { +) -> (TimingValidation, Timing) { let (invalid_timing, timing, _) = validate_timing_with_min_balance_impl(account, Amount::from_u64(0), txn_global_slot); // TODO: In OCaml the returned Timing is actually converted to None/Some(fields of Timing structure) @@ -7958,9 +7652,9 @@ pub fn timing_error_to_user_command_status( } } -pub enum TimingValidation { - InsufficientBalance(bool), - InvalidTiming(bool), +pub enum TimingValidation { + InsufficientBalance(B), + InvalidTiming(B), } #[derive(Debug)] @@ -7970,7 +7664,7 @@ fn validate_timing_with_min_balance_impl( account: &Account, txn_amount: Amount, txn_global_slot: &Slot, -) -> (TimingValidation, Timing, MinBalance) { +) -> (TimingValidation, Timing, MinBalance) { use crate::Timing::*; use TimingValidation::*; diff --git a/ledger/src/scan_state/zkapp_logic.rs b/ledger/src/scan_state/zkapp_logic.rs deleted file mode 100644 index e5aa0a36c7..0000000000 --- a/ledger/src/scan_state/zkapp_logic.rs +++ /dev/null @@ -1,1181 +0,0 @@ -use ark_ff::Zero; -use mina_hasher::Fp; -use mina_signer::CompressedPubKey; -use openmina_core::constants::ConstraintConstants; - -use crate::{ - check_permission, hash_with_kimchi, - scan_state::{ - currency::{Amount, Index, Magnitude, Sgn, Signed, Slot}, - transaction_logic::{ - account_check_timing, cons_zkapp_command_commitment, get_account, is_timed, - local_state::{CallStack, LocalStateEnv, StackFrame}, - protocol_state::GlobalState, - set_account, - zkapp_command::{ - self, AccountUpdate, CallForest, CheckAuthorizationResult, OrIgnore, SetOrKeep, - }, - Env, TimingValidation, TransactionFailure, - }, - }, - sparse_ledger::LedgerIntf, - Account, AuthRequired, ControlTag, Mask, ReceiptChainHash, SetVerificationKey, Timing, TokenId, - ZkAppAccount, TXN_VERSION_CURRENT, -}; - -use super::{ - currency::SlotSpan, - transaction_logic::{ - zkapp_command::{Actions, ACCOUNT_UPDATE_CONS_HASH_PARAM}, - Eff, ExistingOrNew, PerformResult, - }, -}; - -/* - In the OCaml code "asserts" are used to raise an "Assert_failure" exception that is - catched and turn into an error code. We will mimic a similar behaviour using the Result - type and an "__assert" macro. - This code won't panic! -*/ - -macro_rules! __assert { - ($cond:expr $(,)?) => {{ - if !$cond { - let file = file!(); - let line = line!(); - return Err(format!("Assert_failure {file}:{line}")); - } - Ok::<(), String>(()) - }}; -} - -pub struct StartData { - pub account_updates: CallForest, - pub memo_hash: Fp, - pub will_succeed: bool, -} - -pub enum IsStart { - Yes(StartData), - No, - Compute(StartData), -} - -pub struct Handler { - pub perform: fn(Eff) -> PerformResult, -} - -pub fn commitment(account_updates: CallForest) -> ReceiptChainHash { - ReceiptChainHash(account_updates.hash()) -} - -pub fn full_commitment( - account_update: AccountUpdate, - memo_hash: Fp, - commitment: ReceiptChainHash, -) -> ReceiptChainHash { - let fee_payer_hash = account_update.digest(); - ReceiptChainHash(hash_with_kimchi( - ACCOUNT_UPDATE_CONS_HASH_PARAM, - &[memo_hash, fee_payer_hash, commitment.0], - )) -} - -pub fn controller_check( - proof_verifies: bool, - signature_verifies: bool, - perm: AuthRequired, -) -> Result { - __assert!(!(proof_verifies && signature_verifies))?; - let tag = if proof_verifies { - ControlTag::Proof - } else if signature_verifies { - ControlTag::Signature - } else { - ControlTag::NoneGiven - }; - Ok(check_permission(perm, tag)) -} - -#[derive(Clone)] -pub enum ZkAppCommandElt { - ZkAppCommandCommitment(ReceiptChainHash), -} - -fn assert_with_failure_status_tbl( - b: bool, - failure_status_tbl: Vec>, -) -> Result<(), String> { - if !b && !(failure_status_tbl.is_empty()) { - Err(format!("{:?}", failure_status_tbl)) - } else { - __assert!(b) - } -} - -// https://github.com/MinaProtocol/mina/blob/32a91613c388a71f875581ad72276e762242f802/src/lib/mina_ledger/ledger.ml#L211 -fn empty_ledger(depth: usize) -> Mask { - Mask::new_unattached(depth) - //mask.set_parent(parent, None) -} - -fn pop_call_stack(s: &CallStack) -> (StackFrame, CallStack) { - if let Some(a) = s.pop() { - a - } else { - (StackFrame::default(), CallStack::new()) - } -} - -/// https://github.com/MinaProtocol/mina/blob/436023ba41c43a50458a551b7ef7a9ae61670b25/src/lib/transaction_logic/mina_transaction_logic.ml#L1545 -fn account_verification_key_hash(account: &Account) -> Option { - Some(account.zkapp.as_ref()?.verification_key.as_ref()?.hash()) -} - -pub struct GetNextAccountUpdateResult { - pub account_update: AccountUpdate, - pub caller_id: TokenId, - pub account_update_forest: CallForest, - pub new_call_stack: CallStack, - pub new_frame: StackFrame, -} - -pub fn get_next_account_update( - current_forest: StackFrame, - call_stack: CallStack, -) -> Result { - let (next_forest, next_call_stack) = pop_call_stack(&call_stack); - let (current_forest, call_stack) = if current_forest.calls.is_empty() { - (next_forest, next_call_stack) - } else { - (current_forest, call_stack) - }; - - let ((account_update, account_update_forest), remainder_of_current_forest) = - current_forest.calls.pop_exn(); - - let may_use_parents_own_token = account_update.may_use_parents_own_token(); - let may_use_token_inherited_from_parent = account_update.may_use_token_inherited_from_parent(); - - let caller_id = if may_use_token_inherited_from_parent { - current_forest.caller_caller.clone() - } else if may_use_parents_own_token { - current_forest.caller.clone() - } else { - TokenId::default() - }; - - // Cases: - // - [account_update_forest] is empty, [remainder_of_current_forest] is empty. - // Pop from the call stack to get another forest, which is guaranteed to be non-empty. - // The result of popping becomes the "current forest". - // - [account_update_forest] is empty, [remainder_of_current_forest] is non-empty. - // Push nothing to the stack. [remainder_of_current_forest] becomes new "current forest" - // - [account_update_forest] is non-empty, [remainder_of_current_forest] is empty. - // Push nothing to the stack. [account_update_forest] becomes new "current forest" - // - [account_update_forest] is non-empty, [remainder_of_current_forest] is non-empty: - // Push [remainder_of_current_forest] to the stack. [account_update_forest] becomes new "current forest". - - let account_update_forest_empty = account_update_forest.is_empty(); - let remainder_of_current_forest_empty = remainder_of_current_forest.is_empty(); - let (newly_popped_frame, popped_call_stack) = pop_call_stack(&call_stack); - let remainder_of_current_forest_frame = StackFrame { - caller: current_forest.caller.clone(), - caller_caller: current_forest.caller_caller, - calls: remainder_of_current_forest, - }; - - let new_call_stack = if account_update_forest_empty { - if remainder_of_current_forest_empty { - popped_call_stack - } else { - call_stack - } - } else if remainder_of_current_forest_empty { - call_stack - } else { - call_stack.push(&remainder_of_current_forest_frame) - }; - - let new_frame = if account_update_forest_empty { - if remainder_of_current_forest_empty { - newly_popped_frame - } else { - remainder_of_current_forest_frame - } - } else { - let caller = account_update.account_id().derive_token_id(); - let caller_caller = caller_id.clone(); - - StackFrame { - caller, - caller_caller, - calls: account_update_forest.clone(), - } - }; - Ok(GetNextAccountUpdateResult { - account_update, - account_update_forest, - new_frame, - new_call_stack, - caller_id, - }) -} - -pub fn check_account( - public_key: CompressedPubKey, - token_id: TokenId, - (account, loc): (&Account, &ExistingOrNew), -) -> Result -where - L: LedgerIntf, -{ - __assert!(public_key == account.public_key)?; - __assert!(token_id == account.token_id)?; - // IsNew? - match loc { - ExistingOrNew::Existing(_) => Ok(false), - ExistingOrNew::New => Ok(true), - } -} - -pub fn make_zkapp(a: Account) -> Account { - let zkapp = if let zkapp @ Some(_) = a.zkapp { - zkapp - } else { - Some(ZkAppAccount::default().into()) - }; - Account { zkapp, ..a } -} - -pub fn update_action_state( - action_state: [Fp; 5], - actions: Actions, - txn_global_slot: Slot, - last_action_slot: Slot, -) -> ([Fp; 5], Slot) { - let [_s1, _s2, _s3, _s4, _s5] = action_state; - let is_empty = actions.is_empty(); - let s1_updated = actions.push_events(_s1); - let s1 = if is_empty { _s1 } else { s1_updated }; - let is_this_slot = txn_global_slot == last_action_slot; - let is_empty_or_this_slot = is_empty || is_this_slot; - let (s5, s4, s3, s2) = if is_empty_or_this_slot { - (_s5, _s4, _s3, _s2) - } else { - (_s4, _s3, _s2, _s1) - }; - let last_action_slot = if is_empty { - last_action_slot - } else { - txn_global_slot - }; - ([s1, s2, s3, s4, s5], last_action_slot) -} - -pub fn unmake_zkapp(a: Account) -> Account { - let zkapp = a.zkapp.filter(|zkapp| ZkAppAccount::default() != **zkapp); - Account { zkapp, ..a } -} - -pub fn apply( - constraint_constants: &ConstraintConstants, - is_start: IsStart, - _h: &Handler, - (global_state, local_state): (GlobalState, LocalStateEnv), -) -> Result<(GlobalState, LocalStateEnv), String> -where - L: LedgerIntf + Clone, -{ - let is_empty_call_forest = local_state.stack_frame.calls.is_empty(); - - match is_start { - IsStart::Compute(_) => (), - IsStart::Yes(_) => __assert!(is_empty_call_forest)?, - IsStart::No => __assert!(!is_empty_call_forest)?, - }; - - let is_start_ = match is_start { - IsStart::Yes(_) => true, - IsStart::No => false, - IsStart::Compute(_) => is_empty_call_forest, - }; - - let will_succeed = match &is_start { - IsStart::Compute(start_data) => { - if is_start_ { - start_data.will_succeed - } else { - local_state.will_succeed - } - } - IsStart::Yes(start_data) => start_data.will_succeed, - IsStart::No => local_state.will_succeed, - }; - - let mut local_state = local_state; - - if is_start_ { - local_state.ledger = global_state.first_pass_ledger(); - } - local_state.will_succeed = will_succeed; - - let ( - (account_update, remaining, call_stack), - account_update_forest, - local_state, - (a, inclusion_proof), - ) = { - let (to_pop, call_stack) = match &is_start { - IsStart::Compute(start_data) => { - if is_start_ { - ( - StackFrame { - caller: TokenId::default(), - caller_caller: TokenId::default(), - calls: start_data.account_updates.clone(), - }, - CallStack::new(), - ) - } else { - ( - local_state.stack_frame.clone(), - local_state.call_stack.clone(), - ) - } - } - IsStart::Yes(start_data) => ( - StackFrame { - caller: TokenId::default(), - caller_caller: TokenId::default(), - calls: start_data.account_updates.clone(), - }, - CallStack::new(), - ), - IsStart::No => ( - local_state.stack_frame.clone(), - local_state.call_stack.clone(), - ), - }; - - let GetNextAccountUpdateResult { - account_update, - account_update_forest, - new_frame: remaining, - new_call_stack: call_stack, - caller_id, - } = get_next_account_update(to_pop, call_stack)?; - - let mut local_state = local_state.add_check( - TransactionFailure::TokenOwnerNotCaller, - account_update.token_id() == TokenId::default() - || account_update.token_id() == caller_id, - ); - - let (a, inclusion_proof) = - get_account(&mut local_state.ledger, account_update.account_id()); - - let acct = (a, inclusion_proof); - - let (transaction_commitment, full_transaction_commitment) = match &is_start { - IsStart::No => ( - local_state.transaction_commitment, - local_state.full_transaction_commitment, - ), - IsStart::Yes(start_data) | IsStart::Compute(start_data) => { - let tx_commitment_on_start = commitment(remaining.calls.clone()); - let full_tx_commitment_on_start = full_commitment( - account_update.clone(), - start_data.memo_hash, - tx_commitment_on_start.clone(), - ); - if is_start_ { - (tx_commitment_on_start, full_tx_commitment_on_start) - } else { - ( - local_state.transaction_commitment, - local_state.full_transaction_commitment, - ) - } - } - }; - - let local_state = LocalStateEnv { - transaction_commitment, - full_transaction_commitment, - ..local_state - }; - ( - (account_update, remaining, call_stack), - account_update_forest, - local_state, - acct, - ) - }; - - let local_state = LocalStateEnv { - stack_frame: remaining.clone(), - call_stack, - ..local_state - }; - let local_state = local_state.add_new_failure_status_bucket(); - let account_is_new = check_account::( - account_update.public_key(), - account_update.token_id(), - (&a, &inclusion_proof), - )?; - - // delegate to public key if new account using default token - let a = { - let self_delegate = { - let account_update_token_id = account_update.token_id(); - account_is_new && account_update_token_id.is_default() - }; - // in-SNARK, a new account has the empty public key here - // in that case, use the public key from the account update, not the account - - let delegate = if self_delegate { - account_update.public_key() - } else { - a.delegate.unwrap_or_else(CompressedPubKey::empty) - }; - - let delegate = if delegate == CompressedPubKey::empty() { - None - } else { - Some(delegate) - }; - - Account { delegate, ..*a } - }; - - let matching_verification_key_hashes = !(account_update.is_proved()) - || account_verification_key_hash(&a) == account_update.verification_key_hash(); - - let local_state = local_state.add_check( - TransactionFailure::UnexpectedVerificationKeyHash, - matching_verification_key_hashes, - ); - - let PerformResult::LocalState(local_state) = Env::perform(Eff::CheckAccountPrecondition( - account_update.clone(), - a.clone(), - account_is_new, - local_state, - )) else { - unreachable!() - }; - - let protocol_state_predicate_satisfied = - if let PerformResult::Bool(protocol_state_predicate_satisfied) = - Env::perform(Eff::CheckProtocolStatePrecondition( - account_update.protocol_state_precondition().into(), - global_state.clone(), - )) - { - protocol_state_predicate_satisfied - } else { - unreachable!() - }; - - let local_state = local_state.add_check( - TransactionFailure::ProtocolStatePreconditionUnsatisfied, - protocol_state_predicate_satisfied, - ); - - let local_state = { - let valid_while_satisfied = Env::perform(Eff::CheckValidWhilePrecondition( - account_update.valid_while_precondition(), - global_state.clone(), - )) - .to_bool(); - - local_state.add_check( - TransactionFailure::ValidWhilePreconditionUnsatisfied, - valid_while_satisfied, - ) - }; - - let CheckAuthorizationResult { - proof_verifies, - signature_verifies, - } = { - let commitment = if account_update.use_full_commitment() { - local_state.full_transaction_commitment.clone() - } else { - local_state.transaction_commitment.clone() - }; - account_update.check_authorization( - local_state.will_succeed, - commitment.0, - account_update_forest, - ) - }; - - __assert!(proof_verifies == account_update.is_proved())?; - __assert!(signature_verifies == account_update.is_signed())?; - - let local_state = local_state.add_check( - TransactionFailure::FeePayerNonceMustIncrease, - account_update.increment_nonce() || !is_start_, - ); - let local_state = local_state.add_check( - TransactionFailure::FeePayerMustBeSigned, - signature_verifies || !is_start_, - ); - - let precondition_has_constant_nonce = match account_update.account_precondition().nonce() { - OrIgnore::Check(x) => x.is_constant(), - OrIgnore::Ignore => false, - }; - let increments_nonce_and_constrains_its_old_value = - account_update.increment_nonce() && precondition_has_constant_nonce; - let depends_on_the_fee_payers_nonce_and_isnt_the_fee_payer = - account_update.use_full_commitment() && !is_start_; - let does_not_use_a_signature = !signature_verifies; - - let local_state = local_state.add_check( - TransactionFailure::ZkappCommandReplayCheckFailed, - increments_nonce_and_constrains_its_old_value - || depends_on_the_fee_payers_nonce_and_isnt_the_fee_payer - || does_not_use_a_signature, - ); - let a = Account { - token_id: account_update.token_id(), - ..a - }; - let account_update_token_is_default = account_update.token_id() == TokenId::default(); - let account_is_untimed = !is_timed(&a); - - let timing = account_update.timing(); - let has_permission = - controller_check(proof_verifies, signature_verifies, a.permissions.set_timing)?; - - let local_state = local_state.add_check( - TransactionFailure::UpdateNotPermittedTiming, - timing.is_keep() || (account_is_untimed && has_permission), - ); - let timing = timing - .into_map(Some) - .set_or_keep(zkapp_command::Timing::of_account_timing(a.timing.clone())); - - // https://github.com/MinaProtocol/mina/blob/3fe924c80a4d01f418b69f27398f5f93eb652514/src/lib/transaction_logic/mina_transaction_logic.ml#L1197 - let vesting_period = match &timing { - Some(timing) => timing.vesting_period, - None => Timing::Untimed.to_record().vesting_period, - }; - - __assert!(vesting_period > SlotSpan::zero())?; - - let a = Account { - timing: timing - .map(|timing| timing.to_account_timing()) - .unwrap_or(Timing::Untimed), - ..a - }; - - let account_creation_fee = Amount::from_u64(constraint_constants.account_creation_fee); - let implicit_account_creation_fee = account_update.implicit_account_creation_fee(); - - // Check the token for implicit account creation fee payment. - let local_state = local_state.add_check( - TransactionFailure::CannotPayCreationFeeInToken, - (!implicit_account_creation_fee) || account_update_token_is_default, - ); - - // Compute the change to the account balance. - let (local_state, actual_balance_change) = { - let balance_change = account_update.balance_change(); - let neg_creation_fee = Signed::of_unsigned(account_creation_fee).negate(); - - let (balance_change_for_creation, creation_overflow) = - balance_change.add_flagged(neg_creation_fee); - - let pay_creation_fee = account_is_new && implicit_account_creation_fee; - let creation_overflow = pay_creation_fee && creation_overflow; - - let balance_change = if pay_creation_fee { - balance_change_for_creation - } else { - balance_change - }; - - let local_state = local_state.add_check( - TransactionFailure::AmountInsufficientToCreateAccount, - !(pay_creation_fee && (creation_overflow || balance_change.is_neg())), - ); - - (local_state, balance_change) - }; - - let (a, local_state) = { - let pay_creation_fee_from_excess = account_is_new && !implicit_account_creation_fee; - let (balance, failed1) = a.balance.add_signed_amount_flagged(actual_balance_change); - - // println!("[rust] failed1 {}", failed1); - let local_state = local_state.add_check(TransactionFailure::Overflow, !failed1); - let local_state = { - let (excess_minus_creation_fee, excess_update_failed) = - local_state.excess.add_flagged(Signed:: { - magnitude: Amount::from_u64(constraint_constants.account_creation_fee), - sgn: Sgn::Neg, - }); - let local_state = local_state.add_check( - TransactionFailure::LocalExcessOverflow, - !(pay_creation_fee_from_excess && excess_update_failed), - ); - LocalStateEnv { - excess: if pay_creation_fee_from_excess { - excess_minus_creation_fee - } else { - local_state.excess - }, - ..local_state - } - }; - let local_state = { - // Conditionally subtract account creation fee from supply increase - let (supply_increase_minus_creation_fee, supply_increase_update_failed) = local_state - .supply_increase - .add_flagged(Signed::of_unsigned(account_creation_fee).negate()); - let local_state = local_state.add_check( - TransactionFailure::LocalSupplyIncreaseOverflow, - !(account_is_new && supply_increase_update_failed), - ); - LocalStateEnv { - supply_increase: if account_is_new { - supply_increase_minus_creation_fee - } else { - local_state.supply_increase - }, - ..local_state - } - }; - let is_receiver = actual_balance_change.is_non_neg(); - let local_state = { - let controller = if is_receiver { - a.permissions.receive - } else { - a.permissions.send - }; - - let has_permission = controller_check(proof_verifies, signature_verifies, controller)?; - - local_state.add_check( - TransactionFailure::UpdateNotPermittedBalance, - has_permission || actual_balance_change.is_zero(), - ) - }; - let a = Account { balance, ..a }; - (a, local_state) - }; - let txn_global_slot = global_state.block_global_slot; - let (a, local_state) = { - let (invalid_timing, timing) = match account_check_timing(&txn_global_slot, &a) { - (TimingValidation::InsufficientBalance(true), _) => { - panic!("Did not propose a balance change at this timing check!") - } - (TimingValidation::InvalidTiming(true), timing) => (true, timing), - (_, timing) => (false, timing), - }; - let local_state = local_state.add_check( - TransactionFailure::SourceMinimumBalanceViolation, - !invalid_timing, - ); - let a = Account { timing, ..a }; - (a, local_state) - }; - let a = make_zkapp(a); - - // Check that the account can be accessed with the given authorization. - let local_state = { - let has_permission = - controller_check(proof_verifies, signature_verifies, a.permissions.access)?; - local_state.add_check(TransactionFailure::UpdateNotPermittedAccess, has_permission) - }; - - let app_state = account_update.app_state(); - let keeping_app_state = app_state.iter().all(|x| x.is_keep()); - let changing_entire_app_state = app_state.iter().all(|x| x.is_set()); - let zkapp = a.zkapp.unwrap(); - - let proved_state = if keeping_app_state { - zkapp.proved_state - } else if proof_verifies { - if changing_entire_app_state { - true - } else { - zkapp.proved_state - } - } else { - false - }; - let zkapp = ZkAppAccount { - proved_state, - ..*zkapp - }; - let a = Account { - zkapp: Some(zkapp.clone().into()), - ..a - }; - let has_permission = - controller_check(proof_verifies, signature_verifies, a.permissions.edit_state)?; - - let local_state = local_state.add_check( - TransactionFailure::UpdateNotPermittedAppState, - keeping_app_state || has_permission, - ); - let app_state: Vec = app_state - .iter() - .zip(zkapp.app_state.iter()) - .map(|(x, y)| x.set_or_keep(*y)) - .collect(); - let app_state = [ - app_state[0], - app_state[1], - app_state[2], - app_state[3], - app_state[4], - app_state[5], - app_state[6], - app_state[7], - ]; - - let zkapp = ZkAppAccount { app_state, ..zkapp }; - let a = Account { - zkapp: Some(zkapp.clone().into()), - ..a - }; - - let (a, local_state) = { - let verification_key = account_update.verification_key(); - - let SetVerificationKey { auth, txn_version } = &a.permissions.set_verification_key; - - let older_than_current_version = txn_version.lt(&TXN_VERSION_CURRENT); - let original_auth = auth; - - let auth = if older_than_current_version { - original_auth.verification_key_perm_fallback_to_signature_with_older_version() - } else { - *original_auth - }; - - let has_permission = controller_check(proof_verifies, signature_verifies, auth)?; - - let local_state = local_state.add_check( - TransactionFailure::UpdateNotPermittedVerificationKey, - verification_key.is_keep() || has_permission, - ); - let verification_key = match zkapp.verification_key { - Some(vk) => Some(verification_key.set_or_keep(vk)), - None => { - if let SetOrKeep::Set(vk) = verification_key { - Some(vk) - } else { - None - } - } - }; - - let zkapp = ZkAppAccount { - verification_key, - ..zkapp - }; - let a = Account { - zkapp: Some(zkapp.into()), - ..a - }; - (a, local_state) - }; - - let (a, local_state) = { - let actions = account_update.actions(); - let zkapp = a.zkapp.unwrap(); - let last_action_slot = zkapp.last_action_slot; - let (action_state, last_action_slot) = update_action_state( - zkapp.action_state, - actions.clone(), - txn_global_slot, - last_action_slot, - ); - let is_empty = actions.is_empty(); - let has_permission = controller_check( - proof_verifies, - signature_verifies, - a.permissions.edit_action_state, - )?; - - let local_state = local_state.add_check( - TransactionFailure::UpdateNotPermittedActionState, - is_empty || has_permission, - ); - let zkapp = ZkAppAccount { - action_state, - last_action_slot, - ..*zkapp - }; - let a = Account { - zkapp: Some(zkapp.into()), - ..a - }; - (a, local_state) - }; - - let (a, local_state) = { - let zkapp_uri = account_update.zkapp_uri(); - let has_permission = controller_check( - proof_verifies, - signature_verifies, - a.permissions.set_zkapp_uri, - )?; - - let local_state = local_state.add_check( - TransactionFailure::UpdateNotPermittedZkappUri, - zkapp_uri.is_keep() || has_permission, - ); - let zkapp = a.zkapp.map(|x| { - ZkAppAccount { - zkapp_uri: zkapp_uri.set_or_keep(x.zkapp_uri), - ..*x - } - .into() - }); - let a = Account { zkapp, ..a }; - (a, local_state) - }; - - // At this point, all possible changes have been made to the zkapp - // part of an account. Reset zkApp state to [None] if that part - // is unmodified. - let a = unmake_zkapp(a); - // Update token symbol. - let (a, local_state) = { - let token_symbol = account_update.token_symbol(); - let has_permission = controller_check( - proof_verifies, - signature_verifies, - a.permissions.set_token_symbol, - )?; - - let local_state = local_state.add_check( - TransactionFailure::UpdateNotPermittedTokenSymbol, - token_symbol.is_keep() || has_permission, - ); - let token_symbol = token_symbol.set_or_keep(a.token_symbol); - let a = Account { token_symbol, ..a }; - (a, local_state) - }; - - // Update delegate - let (a, local_state) = { - let delegate = account_update.delegate(); - - // for new accounts using the default token, we've already - // set the delegate to the public key - let base_delegate = a.delegate.unwrap_or_else(CompressedPubKey::empty); - - let has_permission = controller_check( - proof_verifies, - signature_verifies, - a.permissions.set_delegate, - )?; - - let local_state = local_state.add_check( - TransactionFailure::UpdateNotPermittedDelegate, - delegate.is_keep() || (has_permission && account_update_token_is_default), - ); - - let delegate = delegate.set_or_keep(base_delegate); - - let delegate = if delegate == CompressedPubKey::empty() { - None - } else { - Some(delegate) - }; - let a = Account { delegate, ..a }; - (a, local_state) - }; - - let (a, local_state) = { - let nonce = a.nonce; - let increment_nonce = account_update.increment_nonce(); - let nonce = if increment_nonce { nonce.incr() } else { nonce }; - let has_permission = controller_check( - proof_verifies, - signature_verifies, - a.permissions.increment_nonce, - )?; - - let local_state = local_state.add_check( - TransactionFailure::UpdateNotPermittedNonce, - !increment_nonce || has_permission, - ); - let a = Account { nonce, ..a }; - (a, local_state) - }; - - let (a, local_state) = { - let voting_for = account_update.voting_for(); - let has_permission = controller_check( - proof_verifies, - signature_verifies, - a.permissions.set_voting_for, - )?; - - let local_state = local_state.add_check( - TransactionFailure::UpdateNotPermittedVotingFor, - voting_for.is_keep() || has_permission, - ); - let voting_for = voting_for.set_or_keep(a.voting_for); - let a = Account { voting_for, ..a }; - (a, local_state) - }; - - let a = { - let new_hash = { - let old_hash = a.receipt_chain_hash; - if signature_verifies || proof_verifies { - let elt = ZkAppCommandElt::ZkAppCommandCommitment( - local_state.full_transaction_commitment.clone(), - ); - cons_zkapp_command_commitment(local_state.account_update_index, elt, &old_hash) - } else { - old_hash - } - }; - Account { - receipt_chain_hash: new_hash, - ..a - } - }; - - let (a, local_state) = { - let permissions = account_update.permissions(); - let has_permission = controller_check( - proof_verifies, - signature_verifies, - a.permissions.set_permissions, - )?; - - let local_state = local_state.add_check( - TransactionFailure::UpdateNotPermittedPermissions, - permissions.is_keep() || has_permission, - ); - let permissions = permissions.set_or_keep(a.permissions); - let a = Account { permissions, ..a }; - (a, local_state) - }; - - let a = match Env::perform(Eff::::InitAccount(account_update.clone(), a)) { - PerformResult::Account(a) => a, - _ => unreachable!(), - }; - - let local_delta = account_update.balance_change().negate(); - let (new_local_fee_excess, overflowed) = { - // We only allow the default token for fees. - __assert!(!is_start_ || (account_update_token_is_default && local_delta.is_non_neg()))?; - - let (new_local_fee_excess, overflow) = local_state.excess.add_flagged(Signed:: { - magnitude: Amount::from_u64(local_delta.magnitude.as_u64()), - sgn: local_delta.sgn, - }); - - let new_local_fee_excess = if account_update_token_is_default { - new_local_fee_excess - } else { - local_state.excess - }; - ( - new_local_fee_excess, - account_update_token_is_default && overflow, - ) - }; - let local_state = LocalStateEnv { - excess: new_local_fee_excess, - ..local_state - }; - let mut local_state = - local_state.add_check(TransactionFailure::LocalExcessOverflow, !overflowed); - - let new_ledger = set_account(&mut local_state.ledger, (a, &inclusion_proof)); - let is_last_account_update = remaining.calls.is_empty(); - let local_state = LocalStateEnv { - ledger: new_ledger.clone(), - transaction_commitment: if is_last_account_update { - ReceiptChainHash(Fp::zero()) - } else { - local_state.transaction_commitment - }, - full_transaction_commitment: if is_last_account_update { - ReceiptChainHash(Fp::zero()) - } else { - local_state.full_transaction_commitment - }, - ..local_state - }; - - let valid_fee_excess = { - let delta_settled = local_state.excess == Signed::::zero(); - is_start_ || !is_last_account_update || delta_settled - }; - let local_state = local_state.add_check(TransactionFailure::InvalidFeeExcess, valid_fee_excess); - - // let is_start_or_last = Bool.(is_start' ||| is_last_account_update) in - // let update_local_excess = is_start_ || is_last_account_update; - // let update_global_state = update_local_excess && local_state.success; - - let is_start_or_last = is_start_ || is_last_account_update; - - let update_global_state_fee_excess = is_start_or_last && local_state.success; - // let update_global_state_fee_excess = - // Bool.(is_start_or_last &&& local_state.success) - // in - - let (global_state, global_excess_update_failed) = { - // let (global_state, global_excess_update_failed, update_global_state) = { - let amt = global_state.fee_excess; - let (res, overflow) = amt.add_flagged(local_state.excess); - let global_excess_update_failed = update_global_state_fee_excess && overflow; - // let update_global_state = update_global_state && !overflow; - let new_amt = if update_global_state_fee_excess { - res - } else { - amt - }; - ( - GlobalState { - fee_excess: new_amt, - ..global_state - }, - global_excess_update_failed, - ) - }; - let local_state = LocalStateEnv { - excess: if is_start_or_last { - Signed::::zero() - } else { - local_state.excess - }, - ..local_state - }; - let local_state = local_state.add_check( - TransactionFailure::GlobalExcessOverflow, - !global_excess_update_failed, - ); - - // add local supply increase in global state - let (new_global_supply_increase, global_supply_increase_update_failed) = { - global_state - .supply_increase() - .add_flagged(local_state.supply_increase) - }; - let local_state = local_state.add_check( - TransactionFailure::GlobalSupplyIncreaseOverflow, - !global_supply_increase_update_failed, - ); - - // The first account_update must succeed. - assert_with_failure_status_tbl( - !is_start_ || local_state.success, - local_state.failure_status_tbl.clone(), - )?; - - // If we are the fee payer (is_start' = true), push the first pass ledger - // and set the local ledger to be the second pass ledger in preparation for - // the children. - let (local_state, global_state) = { - let is_fee_payer = is_start_; - let global_state = - global_state.set_first_pass_ledger(is_fee_payer, local_state.ledger.clone()); - - let local_state = LocalStateEnv { - ledger: if is_fee_payer { - global_state.second_pass_ledger() - } else { - local_state.ledger - }, - ..local_state - }; - - (local_state, global_state) - }; - - // If this is the last account update, and [will_succeed] is false, then - // [success] must also be false. - let any = [ - !is_last_account_update, - local_state.will_succeed, - !local_state.success, - ] - .iter() - .any(|b| *b); - // https://github.com/MinaProtocol/mina/blob/436023ba41c43a50458a551b7ef7a9ae61670b25/src/lib/transaction_logic/mina_transaction_logic.ml#L1207 - assert!(any); - - // If this is the last party and there were no failures, update the second - // pass ledger and the supply increase. - let global_state = { - let is_successful_last_party = is_last_account_update && local_state.success; - let global_state = global_state.set_supply_increase(if is_successful_last_party { - new_global_supply_increase - } else { - global_state.supply_increase() - }); - global_state.set_second_pass_ledger(is_successful_last_party, local_state.ledger.clone()) - }; - - let local_state = LocalStateEnv { - ledger: if is_last_account_update { - L::empty(0) - } else { - local_state.ledger - }, - success: if is_last_account_update { - true - } else { - local_state.success - }, - account_update_index: if is_last_account_update { - Index::zero() - } else { - local_state.account_update_index.incr() - }, - supply_increase: if is_last_account_update { - Signed::zero() - } else { - local_state.supply_increase - }, - will_succeed: if is_last_account_update { - true - } else { - local_state.will_succeed - }, - ..local_state - }; - Ok((global_state, local_state)) -} - -pub fn step( - constraint_constants: &ConstraintConstants, - h: &Handler, - state: (GlobalState, LocalStateEnv), -) -> Result<(GlobalState, LocalStateEnv), String> -where - L: LedgerIntf + Clone, -{ - apply(constraint_constants, IsStart::No, h, state) -} - -pub fn start( - constraint_constants: &ConstraintConstants, - start_data: StartData, - h: &Handler, - state: (GlobalState, LocalStateEnv), -) -> Result<(GlobalState, LocalStateEnv), String> -where - L: LedgerIntf + Clone, -{ - apply(constraint_constants, IsStart::Yes(start_data), h, state) -} diff --git a/ledger/src/sparse_ledger/sparse_ledger.rs b/ledger/src/sparse_ledger/sparse_ledger.rs index 55a6056256..97a4927240 100644 --- a/ledger/src/sparse_ledger/sparse_ledger.rs +++ b/ledger/src/sparse_ledger/sparse_ledger.rs @@ -128,25 +128,20 @@ impl SparseLedger { pub fn apply_zkapp_first_pass_unchecked_with_states( &mut self, + states: &mut Vec<(GlobalState, LocalStateEnv)>, global_slot: Slot, state_view: &ProtocolStateView, fee_excess: Signed, supply_increase: Signed, second_pass_ledger: &Self, zkapp_command: &ZkAppCommand, - ) -> Result< - ( - ZkappCommandPartiallyApplied, - Vec<(GlobalState, LocalStateEnv)>, - ), - String, - > { + ) -> Result, String> { apply_zkapp_command_first_pass_aux( constraint_constants(), global_slot, state_view, - Vec::with_capacity(16), - |mut acc, (global_state, mut local_state)| { + states, + |acc, global_state, local_state| { let GlobalState { first_pass_ledger, second_pass_ledger: _, @@ -154,8 +149,9 @@ impl SparseLedger { supply_increase, protocol_state, block_global_slot, - } = global_state; + } = global_state.clone(); + let mut local_state = local_state.clone(); local_state.ledger = local_state.ledger.copy_content(); acc.insert( @@ -172,7 +168,6 @@ impl SparseLedger { local_state, ), ); - acc }, Some(fee_excess), Some(supply_increase), @@ -183,19 +178,13 @@ impl SparseLedger { pub fn apply_zkapp_second_pass_unchecked_with_states( &mut self, - init: Vec<(GlobalState, LocalStateEnv)>, + init: &mut Vec<(GlobalState, LocalStateEnv)>, c: ZkappCommandPartiallyApplied, - ) -> Result< - ( - ZkappCommandApplied, - Vec<(GlobalState, LocalStateEnv)>, - ), - String, - > { - let (account_update_applied, mut rev_states) = apply_zkapp_command_second_pass_aux( + ) -> Result { + let account_update_applied = apply_zkapp_command_second_pass_aux( constraint_constants(), init, - |mut acc, (global_state, mut local_state)| { + |acc, global_state, local_state| { let GlobalState { first_pass_ledger, second_pass_ledger, @@ -203,8 +192,9 @@ impl SparseLedger { supply_increase, protocol_state, block_global_slot, - } = global_state; + } = global_state.clone(); + let mut local_state = local_state.clone(); local_state.ledger = local_state.ledger.copy_content(); acc.insert( @@ -221,12 +211,13 @@ impl SparseLedger { local_state, ), ); - acc + // acc }, self, c, )?; + let rev_states = init; let will_succeed = account_update_applied.command.status.is_applied(); rev_states.reverse(); @@ -237,8 +228,8 @@ impl SparseLedger { local_state.will_succeed = will_succeed; } - let states = rev_states; - Ok((account_update_applied, states)) + // let states = rev_states; + Ok(account_update_applied) } } diff --git a/ledger/src/staged_ledger/staged_ledger.rs b/ledger/src/staged_ledger/staged_ledger.rs index 1151ec1ffa..9c18088ef8 100644 --- a/ledger/src/staged_ledger/staged_ledger.rs +++ b/ledger/src/staged_ledger/staged_ledger.rs @@ -31,10 +31,11 @@ use crate::{ UserCommand, WithStatus, }, }, - sparse_ledger::{self, SparseLedger}, + sparse_ledger::SparseLedger, split_at, split_at_vec, staged_ledger::{pre_diff_info, resources::IncreaseBy, transaction_validator}, verifier::{Verifier, VerifierError}, + zkapps::non_snark::LedgerNonSnark, AccountId, BaseLedger, Mask, TokenId, }; @@ -77,7 +78,7 @@ pub enum StagedLedgerError { const ZKAPP_LIMIT_PER_BLOCK: Option = None; -pub struct PreStatement { +pub struct PreStatement { partially_applied_transaction: TransactionPartiallyApplied, expected_status: TransactionStatus, accounts_accessed: Vec, @@ -1246,12 +1247,16 @@ impl StagedLedger { supercharge_coinbase: bool, ) -> Result { let work = witness.completed_works(); + let works_count = work.len(); let now = redux::Instant::now(); if skip_verification.is_none() { Self::check_completed_works(logger, verifier, &self.scan_state, work)?; } - eprintln!("verification time={:?}", now.elapsed()); + eprintln!( + "verification time={:?} ({works_count} completed works)", + now.elapsed() + ); let prediff = witness.get( |cmd| Self::check_commands(self.ledger.clone(), verifier, cmd, skip_verification), diff --git a/ledger/src/transaction_pool.rs b/ledger/src/transaction_pool.rs index f6ce8123f7..cda188513b 100644 --- a/ledger/src/transaction_pool.rs +++ b/ledger/src/transaction_pool.rs @@ -203,7 +203,7 @@ pub type ValidCommandWithHash = WithHash; pub mod diff { use super::*; - #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] + #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, strum_macros::Display)] pub enum Error { InsufficientReplaceFee, Duplicate, @@ -1599,54 +1599,13 @@ pub enum ApplyDecision { Reject, } -#[derive(Clone, Debug, Serialize, Deserialize)] -struct Time { - nanoseconds_since_unix_epoch: u64, -} - -impl Time { - #[cfg(target_family = "wasm")] - fn now() -> Self { - // TODO: - // https://github.com/janestreet/time_now/blob/d7e3801d2f120b6723c28429de0dd63b669d47b8/src/time_now_stubs.c#L16 - todo!() - } - - #[cfg(not(target_family = "wasm"))] - fn now() -> Self { - const NANOS_PER_SECOND: u64 = 1000000000; - - let mut tp = libc::timeval { - tv_sec: 0, - tv_usec: 0, - }; - - let result = unsafe { - // Use same syscall than OCaml: - // https://github.com/janestreet/time_now/blob/d7e3801d2f120b6723c28429de0dd63b669d47b8/src/time_now_stubs.c#L30 - libc::gettimeofday(&mut tp, std::ptr::null_mut()) - }; - if result == -1 { - return Self { - nanoseconds_since_unix_epoch: 0, - }; - } - - Self { - nanoseconds_since_unix_epoch: NANOS_PER_SECOND - .wrapping_mul(tp.tv_sec as u64) - .wrapping_add((tp.tv_usec as u64).wrapping_mul(1000)), - } - } -} - const MAX_PER_15_SECONDS: usize = 10; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct TransactionPool { pub pool: IndexedPool, - locally_generated_uncommitted: HashMap, - locally_generated_committed: HashMap, + locally_generated_uncommitted: HashMap, + locally_generated_committed: HashMap, current_batch: usize, remaining_in_batch: usize, pub config: Config, @@ -1964,6 +1923,7 @@ impl TransactionPool { fn apply( &mut self, + time: redux::Timestamp, global_slot_since_genesis: Slot, current_global_slot: Slot, diff: &diff::DiffVerified, @@ -2079,7 +2039,7 @@ impl TransactionPool { continue; }; if !all_dropped_cmd_hashes.contains(&cmd.hash) { - self.register_locally_generated(cmd); + self.register_locally_generated(time, cmd); } } } @@ -2117,6 +2077,7 @@ impl TransactionPool { pub fn unsafe_apply( &mut self, + time: redux::Timestamp, global_slot_since_genesis: Slot, current_global_slot: Slot, diff: &diff::DiffVerified, @@ -2131,6 +2092,7 @@ impl TransactionPool { String, > { let (decision, accepted, rejected) = self.apply( + time, global_slot_since_genesis, current_global_slot, diff, @@ -2140,11 +2102,11 @@ impl TransactionPool { Ok((decision, accepted, rejected)) } - fn register_locally_generated(&mut self, cmd: &ValidCommandWithHash) { + fn register_locally_generated(&mut self, time: redux::Timestamp, cmd: &ValidCommandWithHash) { match self.locally_generated_uncommitted.entry(cmd.clone()) { Entry::Occupied(mut entry) => { - let (time, _batch_num) = entry.get_mut(); - *time = Time::now(); + let (entry_time, _batch_num) = entry.get_mut(); + *entry_time = redux::Timestamp::global_now(); } Entry::Vacant(entry) => { let batch_num = if self.remaining_in_batch > 0 { @@ -2155,7 +2117,7 @@ impl TransactionPool { self.current_batch += 1; self.current_batch }; - entry.insert((Time::now(), Batch::Of(batch_num))); + entry.insert((time, Batch::Of(batch_num))); } } } @@ -2259,7 +2221,7 @@ impl TransactionPool { fn get_rebroadcastable(&mut self, has_timed_out: F) -> Vec> where - F: Fn(&Time) -> bool, + F: Fn(&redux::Timestamp) -> bool, { let log = |has_timed_out: bool, s: &str, cmd: &ValidCommandWithHash| -> bool { if has_timed_out { diff --git a/ledger/src/zkapps/checks.rs b/ledger/src/zkapps/checks.rs new file mode 100644 index 0000000000..13e5e1a88c --- /dev/null +++ b/ledger/src/zkapps/checks.rs @@ -0,0 +1,201 @@ +use mina_hasher::Fp; +use mina_signer::CompressedPubKey; + +use crate::{ + checked_equal_compressed_key, + proofs::{ + field::{field, Boolean, ToBoolean}, + numbers::common::ForZkappCheck, + witness::Witness, + }, + scan_state::transaction_logic::zkapp_command::{ClosedInterval, OrIgnore}, + MyCow, +}; + +/// Check zkapp preconditions +pub trait ZkappCheck { + type T; + + fn zcheck(&self, x: &Self::T, w: &mut Witness) -> Boolean; +} + +impl OrIgnore { + fn make_zcheck( + &self, + default_fn: CompareFn, + compare_fun: DefaultFn, + w: &mut Witness, + ) -> Boolean + where + Ops: ZkappCheckOps, + CompareFn: Fn() -> T, + DefaultFn: Fn(&T, &mut Witness) -> Boolean, + { + let (is_some, value) = match self { + OrIgnore::Check(v) => (Boolean::True, MyCow::Borrow(v)), + OrIgnore::Ignore => (Boolean::False, MyCow::Own(default_fn())), + }; + let is_good = compare_fun(value.as_ref(), w); + Ops::boolean_any([is_some.neg(), is_good], w) + } +} + +impl ZkappCheck for (&OrIgnore, DefaultFn) +where + DefaultFn: Fn() -> Boolean, +{ + type T = Boolean; + + fn zcheck(&self, x: &Self::T, w: &mut Witness) -> Boolean { + let (this, default_fn) = self; + let compare = |value: &Self::T, w: &mut Witness| Ops::is_boolean_equal(x, value, w); + this.make_zcheck::(default_fn, compare, w) + } +} + +impl ZkappCheck for (&OrIgnore, DefaultFn) +where + DefaultFn: Fn() -> Fp, +{ + type T = Fp; + + fn zcheck(&self, x: &Self::T, w: &mut Witness) -> Boolean { + let (this, default_fn) = self; + let compare = |value: &Self::T, w: &mut Witness| Ops::is_field_equal(x, value, w); + this.make_zcheck::(default_fn, compare, w) + } +} + +impl ZkappCheck for (&OrIgnore, DefaultFn) +where + DefaultFn: Fn() -> CompressedPubKey, +{ + type T = CompressedPubKey; + + fn zcheck(&self, x: &Self::T, w: &mut Witness) -> Boolean { + let (this, default_fn) = self; + let compare = + |value: &Self::T, w: &mut Witness| Ops::is_compressed_key_equal(x, value, w); + this.make_zcheck::(default_fn, compare, w) + } +} + +impl ZkappCheck for (&OrIgnore>, DefaultFn) +where + DefaultFn: Fn() -> ClosedInterval, + T: ForZkappCheck, +{ + type T = T; + + fn zcheck(&self, x: &Self::T, w: &mut Witness) -> Boolean { + let (this, default_fn) = self; + let compare = |value: &ClosedInterval, w: &mut Witness| { + Ops::compare_closed_interval(value, x, w) + }; + this.make_zcheck::(default_fn, compare, w) + } +} + +pub trait ZkappCheckOps { + fn compare_closed_interval>( + interval: &ClosedInterval, + value: &T, + w: &mut Witness, + ) -> Boolean; + fn is_boolean_equal(a: &Boolean, b: &Boolean, w: &mut Witness) -> Boolean; + fn is_field_equal(a: &Fp, b: &Fp, w: &mut Witness) -> Boolean; + fn is_compressed_key_equal( + a: &CompressedPubKey, + b: &CompressedPubKey, + w: &mut Witness, + ) -> Boolean; + fn boolean_all(bools: I, w: &mut Witness) -> Boolean + where + I: IntoIterator; + fn boolean_any(bools: I, w: &mut Witness) -> Boolean + where + I: IntoIterator; +} + +pub struct InSnarkOps; +pub struct NonSnarkOps; + +impl ZkappCheckOps for InSnarkOps { + fn compare_closed_interval>( + interval: &ClosedInterval, + value: &T, + w: &mut Witness, + ) -> Boolean { + let ClosedInterval { lower, upper } = interval; + let lower = lower.to_checked(); + let upper = upper.to_checked(); + let x = value.to_checked(); + // We decompose this way because of OCaml evaluation order + let lower_than_upper = >::lte(&x, &upper, w); + let greater_than_lower = >::lte(&lower, &x, w); + Boolean::all(&[greater_than_lower, lower_than_upper], w) + } + fn is_boolean_equal(a: &Boolean, b: &Boolean, w: &mut Witness) -> Boolean { + Boolean::equal(a, b, w) + } + fn is_field_equal(a: &Fp, b: &Fp, w: &mut Witness) -> Boolean { + field::equal(*a, *b, w) + } + fn is_compressed_key_equal( + a: &CompressedPubKey, + b: &CompressedPubKey, + w: &mut Witness, + ) -> Boolean { + checked_equal_compressed_key(a, b, w) + } + fn boolean_all(bools: I, w: &mut Witness) -> Boolean + where + I: IntoIterator, + { + let bools = bools.into_iter().collect::>(); + Boolean::all(&bools, w) + } + fn boolean_any(bools: I, w: &mut Witness) -> Boolean + where + I: IntoIterator, + { + let bools = bools.into_iter().collect::>(); + Boolean::any(&bools, w) + } +} + +impl ZkappCheckOps for NonSnarkOps { + fn compare_closed_interval>( + interval: &ClosedInterval, + value: &T, + _w: &mut Witness, + ) -> Boolean { + let ClosedInterval { lower, upper } = interval; + (lower <= value && value <= upper).to_boolean() + } + fn is_boolean_equal(a: &Boolean, b: &Boolean, _w: &mut Witness) -> Boolean { + (a == b).to_boolean() + } + fn is_field_equal(a: &Fp, b: &Fp, _w: &mut Witness) -> Boolean { + (a == b).to_boolean() + } + fn is_compressed_key_equal( + a: &CompressedPubKey, + b: &CompressedPubKey, + _w: &mut Witness, + ) -> Boolean { + (a == b).to_boolean() + } + fn boolean_all(bools: I, _w: &mut Witness) -> Boolean + where + I: IntoIterator, + { + bools.into_iter().all(|b| b.as_bool()).to_boolean() + } + fn boolean_any(bools: I, _w: &mut Witness) -> Boolean + where + I: IntoIterator, + { + bools.into_iter().any(|b| b.as_bool()).to_boolean() + } +} diff --git a/ledger/src/zkapps/intefaces.rs b/ledger/src/zkapps/intefaces.rs index f8ca334fa7..ae8a9b9856 100644 --- a/ledger/src/zkapps/intefaces.rs +++ b/ledger/src/zkapps/intefaces.rs @@ -13,7 +13,7 @@ use crate::zkapps::zkapp_logic; use crate::scan_state::transaction_logic::zkapp_command::{ self, CheckAuthorizationResult, SetOrKeep, }; -use crate::scan_state::transaction_logic::TransactionFailure; +use crate::scan_state::transaction_logic::{TimingValidation, TransactionFailure}; use crate::sparse_ledger::LedgerIntf; use crate::{AccountId, AuthRequired, MyCow, ReceiptChainHash, TokenId, ZkAppAccount}; @@ -81,8 +81,7 @@ pub trait ZkappHandler { global_state: &mut Self::GlobalState, w: &mut Self::W, ) -> Self::Bool; - fn init_account(account_update: &Self::AccountUpdate, account: &Self::Account) - -> Self::Account; + fn init_account(account_update: &Self::AccountUpdate, account: Self::Account) -> Self::Account; } pub struct Opt { @@ -90,6 +89,21 @@ pub struct Opt { pub data: T, } +impl Opt { + pub fn from_option(opt: Option) -> Self { + match opt { + Some(data) => Self { + is_some: Boolean::True, + data, + }, + None => Self { + is_some: Boolean::False, + data: T::default(), + }, + } + } +} + impl Opt<(A, B)> { pub fn unzip(self) -> (Opt, Opt) { let Self { @@ -182,6 +196,7 @@ pub trait GlobalSlotSinceGenesisInterface { type Bool: BoolInterface; fn equal(&self, other: &Self, w: &mut Self::W) -> Self::Bool; + fn exists_no_check(self, w: &mut Self::W) -> Self; } pub trait GlobalSlotSpanInterface { @@ -320,11 +335,11 @@ where type CallForest: CallForestInterface; type Bool: BoolInterface; type SignedAmount: SignedAmountInterface; + type VerificationKeyHash: VerificationKeyHashInterface; // Only difference in our Rust code is the `WithHash` fn body(&self) -> &crate::scan_state::transaction_logic::zkapp_command::Body; - fn set(&mut self, new: Self); - fn verification_key_hash(&self) -> Fp; + fn verification_key_hash(&self) -> Self::VerificationKeyHash; fn is_proved(&self) -> Self::Bool; fn is_signed(&self) -> Self::Bool; fn check_authorization( @@ -372,7 +387,7 @@ pub trait ControllerInterface { auth: &AuthRequired, single_data: &Self::SingleData, w: &mut Self::W, - ) -> Self::Bool; + ) -> Result; fn verification_key_perm_fallback_to_signature_with_older_version( auth: &AuthRequired, @@ -404,7 +419,7 @@ where fn and(a: Self, b: Self, w: &mut Self::W) -> Self; fn equal(a: Self, b: Self, w: &mut Self::W) -> Self; fn all(bs: &[Self], w: &mut Self::W) -> Self; - fn assert_any(bs: &[Self], w: &mut Self::W); + fn assert_any(bs: &[Self], w: &mut Self::W) -> Result<(), String>; fn assert_with_failure_status_tbl( b: Self, table: &Self::FailureStatusTable, @@ -434,6 +449,7 @@ where type Bool: BoolInterface; type Balance: BalanceInterface; type GlobalSlot: GlobalSlotSinceGenesisInterface; + type VerificationKeyHash: VerificationKeyHashInterface; type D; fn register_verification_key(&self, data: &Self::D, w: &mut Self::W); @@ -442,7 +458,7 @@ where fn set_delegate(&mut self, new: CompressedPubKey); fn zkapp(&self) -> MyCow; fn zkapp_mut(&mut self) -> &mut ZkAppAccount; - fn verification_key_hash(&self) -> Fp; + fn verification_key_hash(&self) -> Self::VerificationKeyHash; fn set_token_id(&mut self, token_id: TokenId); fn is_timed(&self) -> Self::Bool; fn balance(&self) -> Self::Balance; @@ -451,7 +467,7 @@ where &self, txn_global_slot: &Self::GlobalSlot, w: &mut Self::W, - ) -> (Self::Bool, crate::Timing); + ) -> (TimingValidation, crate::Timing); fn make_zkapp(&mut self); fn unmake_zkapp(&mut self); fn proved_state(&self) -> Self::Bool; @@ -461,36 +477,44 @@ where fn set_last_action_slot(&mut self, slot: Self::GlobalSlot); } -pub trait LedgerInterface { +pub trait LedgerInterface: LedgerIntf + Clone { type W: WitnessGenerator; type AccountUpdate: AccountUpdateInterface; type Account: AccountInterface; type Bool: BoolInterface; type InclusionProof; - fn empty() -> Self; + fn empty(depth: usize) -> Self; fn get_account( &self, account_update: &Self::AccountUpdate, w: &mut Self::W, - ) -> (Self::Account, Self::InclusionProof); - fn set_account(&mut self, account: (Self::Account, Self::InclusionProof), w: &mut Self::W); + ) -> Result<(Self::Account, Self::InclusionProof), String>; + fn set_account( + &mut self, + account: (Self::Account, Self::InclusionProof), + w: &mut Self::W, + ) -> Result<(), String>; fn check_inclusion(&self, account: &(Self::Account, Self::InclusionProof), w: &mut Self::W); fn check_account( public_key: &CompressedPubKey, token_id: &TokenId, account: (&Self::Account, &Self::InclusionProof), w: &mut Self::W, - ) -> Self::Bool; - fn exists_no_check(self, w: &mut Self::W) -> Self; - fn exists_no_check_on_bool(self, b: Self::Bool, w: &mut Self::W) -> Self; + ) -> Result; + fn exists_no_check(self, _w: &mut Self::W) -> Self { + self + } + fn exists_no_check_on_bool(self, _b: Self::Bool, _w: &mut Self::W) -> Self { + self + } } pub trait VerificationKeyHashInterface { type W: WitnessGenerator; type Bool: BoolInterface; - fn equal(a: Fp, b: Fp, w: &mut Self::W) -> Self::Bool; + fn equal(a: &Self, b: &Self, w: &mut Self::W) -> Self::Bool; } pub trait SetOrKeepInterface { @@ -551,15 +575,12 @@ pub trait ZkappApplication where Self: Sized, { - type Ledger: LedgerIntf - + Clone - + ToFieldElements - + LedgerInterface< - W = Self::WitnessGenerator, - AccountUpdate = Self::AccountUpdate, - Account = Self::Account, - Bool = Self::Bool, - >; + type Ledger: LedgerInterface< + W = Self::WitnessGenerator, + AccountUpdate = Self::AccountUpdate, + Account = Self::Account, + Bool = Self::Bool, + >; type SignedAmount: SignedAmountInterface + std::fmt::Debug + Clone @@ -572,10 +593,11 @@ where SignedAmount = Self::SignedAmount, >; type Index: IndexInterface + Clone + ToFieldElements; - type GlobalSlotSinceGenesis: GlobalSlotSinceGenesisInterface - + ToFieldElements; + type GlobalSlotSinceGenesis: GlobalSlotSinceGenesisInterface< + W = Self::WitnessGenerator, + Bool = Self::Bool, + >; type StackFrame: StackFrameInterface - + ToFieldElements + std::fmt::Debug + Clone; type CallForest: CallForestInterface< @@ -599,6 +621,7 @@ where SingleData = Self::SingleData, Bool = Self::Bool, SignedAmount = Self::SignedAmount, + VerificationKeyHash = Self::VerificationKeyHash, >; type AccountId: AccountIdInterface; type TokenId: TokenIdInterface; @@ -620,6 +643,7 @@ where Bool = Self::Bool, Balance = Self::Balance, GlobalSlot = Self::GlobalSlotSinceGenesis, + VerificationKeyHash = Self::VerificationKeyHash, >; type VerificationKeyHash: VerificationKeyHashInterface< W = Self::WitnessGenerator, diff --git a/ledger/src/zkapps/mod.rs b/ledger/src/zkapps/mod.rs index 740ed5d3c9..525a721a5c 100644 --- a/ledger/src/zkapps/mod.rs +++ b/ledger/src/zkapps/mod.rs @@ -1,3 +1,4 @@ +pub mod checks; pub mod intefaces; pub mod non_snark; pub mod snark; diff --git a/ledger/src/zkapps/non_snark.rs b/ledger/src/zkapps/non_snark.rs index 4455af5fdc..17a1ad4629 100644 --- a/ledger/src/zkapps/non_snark.rs +++ b/ledger/src/zkapps/non_snark.rs @@ -1,31 +1,118 @@ #![allow(unused)] +use std::marker::PhantomData; + use mina_hasher::Fp; +use mina_signer::CompressedPubKey; use crate::{ + check_permission, proofs::{ - field::{Boolean, FieldWitness}, + field::{Boolean, FieldWitness, ToBoolean}, to_field_elements::ToFieldElements, transaction::Check, + witness::Witness, + zkapp::StartDataSkeleton, }, scan_state::{ - currency::{Amount, Index, Signed}, + currency::{Amount, Balance, Index, Magnitude, Signed, Slot, SlotSpan, TxnVersion}, transaction_logic::{ + account_check_timing, local_state::{CallStack, StackFrame}, - zkapp_command::{AccountUpdate, CallForest, CheckAuthorizationResult}, + protocol_state::GlobalStateSkeleton, + set_with_location, + zkapp_command::{ + self, AccountPreconditions, AccountUpdate, CallForest, CheckAuthorizationResult, + SetOrKeep, + }, + zkapp_statement::TransactionCommitment, + ExistingOrNew, TimingValidation, TransactionFailure, }, }, + sparse_ledger::{LedgerIntf, SparseLedger}, + zkapps::checks::ZkappCheck, + Account, AccountId, AuthRequired, ControlTag, Mask, MyCow, TokenId, ZkAppAccount, + TXN_VERSION_CURRENT, }; -use super::intefaces::{ - AccountUpdateInterface, AmountInterface, BoolInterface, BranchEvaluation, BranchInterface, - BranchParam, CallForestInterface, CallStackInterface, IndexInterface, Opt, - SignedAmountBranchParam, SignedAmountInterface, StackFrameInterface, StackFrameMakeParams, - StackInterface, WitnessGenerator, +use super::{ + checks::NonSnarkOps, + intefaces::{ + AccountIdInterface, AccountInterface, AccountUpdateInterface, ActionsInterface, + AmountInterface, BalanceInterface, BoolInterface, BranchEvaluation, BranchInterface, + BranchParam, CallForestInterface, CallStackInterface, ControllerInterface, + GlobalSlotSinceGenesisInterface, GlobalSlotSpanInterface, GlobalStateInterface, + IndexInterface, LedgerInterface, LocalStateInterface, Opt, ReceiptChainHashInterface, + SetOrKeepInterface, SignedAmountBranchParam, SignedAmountInterface, StackFrameInterface, + StackFrameMakeParams, StackInterface, TokenIdInterface, TransactionCommitmentInterface, + TxnVersionInterface, VerificationKeyHashInterface, WitnessGenerator, ZkappApplication, + ZkappHandler, + }, + zkapp_logic::{self, ApplyZkappParams, ZkAppCommandElt}, }; +pub type GlobalStateForNonSnark = GlobalStateSkeleton< + L, // ledger + Signed, // fee_excess & supply_increase + Slot, // block_global_slot +>; + +type NonSnarkVerificationKeyHash = Option; +pub struct NonSnarkController; +pub struct NonSnarkSetOrKeep; +pub struct NonSnarkGlobalSlotSpan; +pub struct NonSnarkActions; +pub struct NonSnarkReceiptChainHash; +pub struct NonSnarkHandler(PhantomData); + +#[derive(Clone, Debug)] +pub struct ZkappNonSnark(PhantomData); + +/// Helper trait to avoid typing the whole `LedgerInterface<..> everywhere` +pub trait LedgerNonSnark +where + Self: LedgerInterface, +{ +} +impl LedgerNonSnark for T where + T: LedgerInterface +{ +} + +impl ZkappApplication for ZkappNonSnark { + type Ledger = L; + type SignedAmount = Signed; + type Amount = Amount; + type Balance = Balance; + type Index = Index; + type GlobalSlotSinceGenesis = Slot; + type StackFrame = StackFrame; + type CallForest = CallForest; + type CallStack = CallStack; + type GlobalState = GlobalStateForNonSnark; + type AccountUpdate = AccountUpdate; + type AccountId = AccountId; + type TokenId = TokenId; + type Bool = bool; + type TransactionCommitment = TransactionCommitment; + type FailureStatusTable = Vec>; + type LocalState = zkapp_logic::LocalState; + type Account = Account; + type VerificationKeyHash = NonSnarkVerificationKeyHash; + type SingleData = (); + type Controller = NonSnarkController; + type TxnVersion = TxnVersion; + type SetOrKeep = NonSnarkSetOrKeep; + type GlobalSlotSpan = NonSnarkGlobalSlotSpan; + type Actions = NonSnarkActions; + type ReceiptChainHash = NonSnarkReceiptChainHash; + type Handler = NonSnarkHandler; + type Branch = NonSnarkBranch; + type WitnessGenerator = (); +} + impl WitnessGenerator for () { - type Bool = Boolean; + type Bool = bool; fn exists(&mut self, data: T) -> T where @@ -47,71 +134,392 @@ impl WitnessGenerator for () { } } +impl ZkappHandler for NonSnarkHandler { + type Z = ZkappNonSnark; + type AccountUpdate = AccountUpdate; + type Account = Account; + type Bool = bool; + type W = (); + type GlobalState = GlobalStateForNonSnark; + + fn check_account_precondition( + account_update: &Self::AccountUpdate, + account: &Self::Account, + new_account: Self::Bool, + local_state: &mut zkapp_logic::LocalState>, + w: &mut Self::W, + ) { + let precondition_account = &account_update.body.preconditions.account; + let check = |failure, b: Boolean, _: &mut Witness| { + zkapp_logic::LocalState::>::add_check( + local_state, + failure, + b.as_bool(), + w, + ); + }; + let mut w = Witness::empty(); + precondition_account.zcheck::( + new_account.to_boolean(), + account, + check, + &mut w, + ); + } + + fn check_protocol_state_precondition( + protocol_state_predicate: &zkapp_command::ZkAppPreconditions, + global_state: &mut Self::GlobalState, + w: &mut Self::W, + ) -> Self::Bool { + let mut w = Witness::empty(); + protocol_state_predicate + .zcheck::(&global_state.protocol_state, &mut w) + .as_bool() + } + + fn check_valid_while_precondition( + valid_while: &zkapp_command::Numeric, + global_state: &mut Self::GlobalState, + w: &mut Self::W, + ) -> Self::Bool { + use zkapp_command::ClosedInterval; + let mut w = Witness::empty(); + (valid_while, ClosedInterval::min_max) + .zcheck::(&global_state.block_global_slot, &mut w) + .as_bool() + } + + fn init_account( + _account_update: &Self::AccountUpdate, + account: Self::Account, + ) -> Self::Account { + account + } +} + +impl ReceiptChainHashInterface for NonSnarkReceiptChainHash { + type W = (); + type Index = Index; + + fn cons_zkapp_command_commitment( + index: Self::Index, + element: Fp, + other: crate::ReceiptChainHash, + w: &mut Self::W, + ) -> crate::ReceiptChainHash { + use crate::scan_state::transaction_logic::cons_zkapp_command_commitment; + + cons_zkapp_command_commitment( + index, + ZkAppCommandElt::ZkAppCommandCommitment(crate::ReceiptChainHash(element)), + &other, + ) + } +} + +impl ActionsInterface for NonSnarkActions { + type W = (); + type Bool = bool; + + fn is_empty( + actions: &crate::scan_state::transaction_logic::zkapp_command::Actions, + _w: &mut Self::W, + ) -> Self::Bool { + actions.is_empty() + } + + fn push_events( + event: Fp, + actions: &crate::scan_state::transaction_logic::zkapp_command::Actions, + _w: &mut Self::W, + ) -> Fp { + actions.push_events(event) + } +} + +impl SetOrKeepInterface for NonSnarkSetOrKeep { + type Bool = bool; + + fn is_keep(set_or_keep: &SetOrKeep) -> Self::Bool { + set_or_keep.is_keep() + } + + fn is_set(set_or_keep: &SetOrKeep) -> Self::Bool { + set_or_keep.is_set() + } +} + +impl GlobalSlotSpanInterface for NonSnarkGlobalSlotSpan { + type W = (); + type Bool = bool; + type SlotSpan = SlotSpan; + + fn greater_than(this: &Self::SlotSpan, other: &Self::SlotSpan, w: &mut Self::W) -> Self::Bool { + this > other + } +} + +impl TxnVersionInterface for TxnVersion { + type W = (); + type Bool = bool; + + fn equal_to_current(version: TxnVersion, w: &mut Self::W) -> Self::Bool { + version == TXN_VERSION_CURRENT + } + + fn older_than_current(version: TxnVersion, w: &mut Self::W) -> Self::Bool { + version < TXN_VERSION_CURRENT + } +} + +impl VerificationKeyHashInterface for NonSnarkVerificationKeyHash { + type W = (); + type Bool = bool; + + fn equal(a: &Self, b: &Self, _w: &mut Self::W) -> Self::Bool { + a == b + } +} + +impl TransactionCommitmentInterface for TransactionCommitment { + type AccountUpdate = AccountUpdate; + type CallForest = CallForest; + type W = (); + + fn empty() -> Fp { + let TransactionCommitment(fp) = TransactionCommitment::empty(); + fp + } + fn commitment(account_updates: &Self::CallForest) -> Fp { + let account_updates_hash = account_updates.hash(); + let TransactionCommitment(fp) = TransactionCommitment::create(account_updates_hash); + fp + } + fn full_commitment( + account_update: &Self::AccountUpdate, + memo_hash: Fp, + commitment: Fp, + w: &mut Self::W, + ) -> Fp { + // when called from Zkapp_command_logic.apply, the account_update is the fee payer + let fee_payer_hash = account_update.digest(); + let TransactionCommitment(fp) = + TransactionCommitment(commitment).create_complete(memo_hash, fee_payer_hash); + fp + } +} + +impl AccountIdInterface for AccountId { + type W = (); + + fn derive_token_id(account_id: &AccountId, w: &mut Self::W) -> TokenId { + account_id.derive_token_id() + } +} + +impl TokenIdInterface for TokenId { + type W = (); + type Bool = bool; + + fn equal(a: &TokenId, b: &TokenId, w: &mut Self::W) -> Self::Bool { + a == b + } +} + +impl LocalStateInterface for zkapp_logic::LocalState> { + type Z = ZkappNonSnark; + type Bool = bool; + type W = (); + + fn add_check( + local: &mut zkapp_logic::LocalState, + failure: TransactionFailure, + b: Self::Bool, + w: &mut Self::W, + ) { + if !b { + local.failure_status_tbl[0].insert(0, failure); + } + local.success = local.success && b; + } + + fn add_new_failure_status_bucket(local: &mut zkapp_logic::LocalState) { + local.failure_status_tbl.insert(0, Vec::new()); + } +} + impl AmountInterface for Amount { type W = (); - type Bool = Boolean; + type Bool = bool; fn zero() -> Self { - todo!() + ::zero() } fn of_constant_fee(fee: crate::scan_state::currency::Fee) -> Self { - todo!() + Amount::of_fee(&fee) + } +} + +impl BalanceInterface for Balance { + type W = (); + type Bool = bool; + type Amount = Amount; + type SignedAmount = Signed; + + fn add_signed_amount_flagged( + &self, + signed_amount: Self::SignedAmount, + _w: &mut Self::W, + ) -> (Self, Self::Bool) { + self.add_signed_amount_flagged(signed_amount) } } impl SignedAmountInterface for Signed { type W = (); - type Bool = Boolean; + type Bool = bool; type Amount = Amount; fn zero() -> Self { - todo!() + Self::zero() } fn is_neg(&self) -> Self::Bool { - todo!() + self.is_neg() } - fn equal(&self, other: &Self, w: &mut Self::W) -> Self::Bool { - todo!() + fn equal(&self, other: &Self, _w: &mut Self::W) -> Self::Bool { + (self == other) } fn is_non_neg(&self) -> Self::Bool { - todo!() + self.is_non_neg() } fn negate(&self) -> Self { - todo!() + self.negate() } - fn add_flagged(&self, other: &Self, w: &mut Self::W) -> (Self, Self::Bool) { - todo!() + fn add_flagged(&self, other: &Self, _w: &mut Self::W) -> (Self, Self::Bool) { + self.add_flagged(*other) } fn of_unsigned(unsigned: Self::Amount) -> Self { - todo!() + Self::of_unsigned(unsigned) } fn on_if<'a>( b: Self::Bool, param: SignedAmountBranchParam<&'a Self>, w: &mut Self::W, ) -> &'a Self { - todo!() + let SignedAmountBranchParam { on_true, on_false } = param; + match b { + true => on_true, + false => on_false, + } + } +} + +impl GlobalSlotSinceGenesisInterface for Slot { + type W = (); + type Bool = bool; + + fn equal(&self, other: &Self, w: &mut Self::W) -> Self::Bool { + self == other + } + + fn exists_no_check(self, w: &mut Self::W) -> Self { + self + } +} + +impl GlobalStateInterface for GlobalStateForNonSnark { + type Ledger = L; + type W = (); + type Bool = bool; + type SignedAmount = Signed; + type GlobalSlotSinceGenesis = Slot; + + fn first_pass_ledger(&self) -> Self::Ledger { + self.first_pass_ledger.create_masked() + } + fn set_first_pass_ledger( + &mut self, + should_update: Self::Bool, + ledger: &Self::Ledger, + _w: &mut Self::W, + ) { + if should_update { + self.first_pass_ledger.apply_mask(ledger.clone()); + } + } + fn second_pass_ledger(&self) -> Self::Ledger { + self.second_pass_ledger.create_masked() + } + fn set_second_pass_ledger( + &mut self, + should_update: Self::Bool, + ledger: &Self::Ledger, + _w: &mut Self::W, + ) { + if should_update { + self.second_pass_ledger.apply_mask(ledger.clone()); + } + } + fn fee_excess(&self) -> Self::SignedAmount { + self.fee_excess + } + fn set_fee_excess(&mut self, fee_excess: Self::SignedAmount) { + self.fee_excess = fee_excess; + } + fn supply_increase(&self) -> Self::SignedAmount { + self.supply_increase + } + fn set_supply_increase(&mut self, supply_increase: Self::SignedAmount) { + self.supply_increase = supply_increase; + } + fn block_global_slot(&self) -> Self::GlobalSlotSinceGenesis { + self.block_global_slot } } impl StackFrameInterface for StackFrame { type Calls = CallForest; type W = (); - type Bool = Boolean; + type Bool = bool; fn caller(&self) -> crate::TokenId { - todo!() + let Self { + caller, + caller_caller: _, + calls: _, + } = self; + caller.clone() } fn caller_caller(&self) -> crate::TokenId { - todo!() + let Self { + caller: _, + caller_caller, + calls: _, + } = self; + caller_caller.clone() } fn calls(&self) -> &CallForest { - todo!() + let Self { + caller: _, + caller_caller: _, + calls, + } = self; + calls } fn make(params: StackFrameMakeParams<'_, Self::Calls>) -> Self { - todo!() + let StackFrameMakeParams { + caller, + caller_caller, + calls, + } = params; + Self { + caller, + caller_caller, + calls: calls.clone(), + } } fn make_default(params: StackFrameMakeParams<'_, Self::Calls>) -> Self { - todo!() + Self::make(params) // No difference in non-snark } fn on_if Self, F2: FnOnce(&mut Self::W) -> Self>( b: Self::Bool, @@ -121,28 +529,34 @@ impl StackFrameInterface for StackFrame { let BranchParam { on_true, on_false } = param; match b { - Boolean::True => on_true.eval(w), - Boolean::False => on_false.eval(w), + true => on_true.eval(w), + false => on_false.eval(w), } } } +impl ToFieldElements for CallStack { + fn to_field_elements(&self, fields: &mut Vec) { + unreachable!() + } +} + impl StackInterface for CallStack { type Elt = StackFrame; type W = (); - type Bool = Boolean; + type Bool = bool; fn empty() -> Self { - todo!() + Self::default() } - fn is_empty(&self, w: &mut Self::W) -> Boolean { - todo!() + fn is_empty(&self, _w: &mut Self::W) -> Self::Bool { + self.is_empty() } - fn pop(&self, w: &mut Self::W) -> Opt<(Self::Elt, Self)> { - todo!() + fn pop(&self, _w: &mut Self::W) -> Opt<(Self::Elt, Self)> { + Opt::from_option(self.pop()) } - fn push(elt: Self::Elt, onto: Self, w: &mut Self::W) -> Self { - todo!() + fn push(elt: Self::Elt, onto: Self, _w: &mut Self::W) -> Self { + onto.push(&elt) } } @@ -152,68 +566,182 @@ impl CallStackInterface for CallStack { impl IndexInterface for Index { fn zero() -> Self { - todo!() + ::zero() } fn succ(&self) -> Self { - todo!() + self.incr() } } impl CallForestInterface for CallForest { type W = (); type AccountUpdate = AccountUpdate; - type Bool = Boolean; + type Bool = bool; fn empty() -> Self { - todo!() + Self::empty() } - fn is_empty(&self, w: &mut Self::W) -> Boolean { - todo!() + fn is_empty(&self, _w: &mut Self::W) -> Self::Bool { + self.is_empty() } - fn pop_exn(&self, w: &mut Self::W) -> ((AccountUpdate, Self), Self) { - todo!() + fn pop_exn(&self, _w: &mut Self::W) -> ((AccountUpdate, Self), Self) { + self.pop_exn() } } -impl BoolInterface for Boolean { +impl BoolInterface for bool { type W = (); - type FailureStatusTable = (); + type FailureStatusTable = Vec>; fn as_boolean(&self) -> Boolean { - *self + self.to_boolean() } fn of_boolean(b: Boolean) -> Self { - b + b.as_bool() } fn true_() -> Self { - Boolean::True + true } fn false_() -> Self { - Boolean::False + false } fn neg(&self) -> Self { - self.neg() + !self } fn or(a: Self, b: Self, w: &mut Self::W) -> Self { - todo!() + a || b } fn and(a: Self, b: Self, w: &mut Self::W) -> Self { - todo!() + a && b } fn equal(a: Self, b: Self, w: &mut Self::W) -> Self { - todo!() + a == b } fn all(bs: &[Self], w: &mut Self::W) -> Self { - todo!() + bs.iter().all(|b| *b) } - fn assert_any(bs: &[Self], w: &mut Self::W) { - todo!() + fn assert_any(bs: &[Self], w: &mut Self::W) -> Result<(), String> { + if !bs.iter().any(|b| *b) { + return Err("Bool::assert_any failed".to_string()); + } + Ok(()) } fn assert_with_failure_status_tbl( b: Self, - table: &Self::FailureStatusTable, + failure_status_tbl: &Self::FailureStatusTable, ) -> Result<(), String> { - todo!() + if !b && !(failure_status_tbl.is_empty()) { + Err(format!("{:?}", failure_status_tbl)) + } else if !b { + Err("assert_with_failure_status_tbl failed".to_string()) + } else { + Ok(()) + } + } +} + +impl AccountInterface for Account { + type W = (); + type Bool = bool; + type Balance = Balance; + type GlobalSlot = Slot; + type D = (); + type VerificationKeyHash = NonSnarkVerificationKeyHash; + + fn register_verification_key(&self, data: &Self::D, w: &mut Self::W) { + // Nothing + } + + fn get(&self) -> &Account { + self + } + + fn get_mut(&mut self) -> &mut Account { + self + } + + fn set_delegate(&mut self, new: CompressedPubKey) { + self.delegate = if new == CompressedPubKey::empty() { + None + } else { + Some(new) + }; + } + + fn zkapp(&self) -> MyCow { + match self.zkapp.as_ref() { + Some(zkapp) => MyCow::Borrow(zkapp), + None => MyCow::Own(ZkAppAccount::default()), + } + } + + fn zkapp_mut(&mut self) -> &mut ZkAppAccount { + // `unwrap`: `make_zkapp` is supposed to be called before `zkapp_mut` + self.zkapp.as_mut().unwrap() + } + + fn verification_key_hash(&self) -> NonSnarkVerificationKeyHash { + Some(self.zkapp.as_ref()?.verification_key.as_ref()?.hash()) + } + + fn set_token_id(&mut self, token_id: TokenId) { + self.token_id = token_id; + } + + fn is_timed(&self) -> Self::Bool { + match &self.timing { + crate::Timing::Untimed => false, + crate::Timing::Timed { .. } => true, + } + } + + fn balance(&self) -> Self::Balance { + self.balance + } + + fn set_balance(&mut self, balance: Self::Balance) { + self.balance = balance; + } + + fn check_timing( + &self, + txn_global_slot: &Self::GlobalSlot, + w: &mut Self::W, + ) -> (TimingValidation, crate::Timing) { + account_check_timing(txn_global_slot, self) + } + + fn make_zkapp(&mut self) { + if self.zkapp.is_none() { + // ZkAppAccount::default + self.zkapp = Some(Box::default()); + } + } + + fn unmake_zkapp(&mut self) { + if self.zkapp.as_ref().map(|z| z.is_default()).unwrap_or(false) { + self.zkapp = None; + } + } + + fn proved_state(&self) -> Self::Bool { + self.zkapp().proved_state + } + + fn set_proved_state(&mut self, proved_state: Self::Bool) { + self.zkapp_mut().proved_state = proved_state; + } + + fn app_state(&self) -> [Fp; 8] { + self.zkapp().app_state + } + + fn last_action_slot(&self) -> Self::GlobalSlot { + self.zkapp().last_action_slot + } + + fn set_last_action_slot(&mut self, slot: Self::GlobalSlot) { + self.zkapp_mut().last_action_slot = slot; } } @@ -221,8 +749,9 @@ impl AccountUpdateInterface for AccountUpdate { type W = (); type SingleData = (); type CallForest = CallForest; - type Bool = Boolean; + type Bool = bool; type SignedAmount = Signed; + type VerificationKeyHash = NonSnarkVerificationKeyHash; fn body(&self) -> &crate::scan_state::transaction_logic::zkapp_command::Body { let Self { @@ -231,46 +760,101 @@ impl AccountUpdateInterface for AccountUpdate { } = self; body } - fn set(&mut self, new: Self) { - todo!() - } - fn verification_key_hash(&self) -> Fp { - todo!() + fn is_proved(&self) -> Self::Bool { + self.body().authorization_kind.is_proved() } - fn is_proved(&self) -> Boolean { - todo!() + fn is_signed(&self) -> Self::Bool { + self.body().authorization_kind.is_signed() } - fn is_signed(&self) -> Boolean { - todo!() + fn verification_key_hash(&self) -> Self::VerificationKeyHash { + use crate::scan_state::transaction_logic::zkapp_command::AuthorizationKind::*; + + match &self.body().authorization_kind { + Proof(vk_hash) => Some(*vk_hash), + NoneGiven | Signature => None, + } } fn check_authorization( &self, - will_succeed: Boolean, + will_succeed: Self::Bool, commitment: Fp, calls: &Self::CallForest, single_data: &Self::SingleData, w: &mut Self::W, - ) -> CheckAuthorizationResult { - todo!() + ) -> CheckAuthorizationResult { + use crate::scan_state::transaction_logic::zkapp_command::Control::*; + + let (proof_verifies, signature_verifies) = match &self.authorization { + Signature(_) => (false, true), + Proof(_) => (true, false), + NoneGiven => (false, false), + }; + CheckAuthorizationResult { + proof_verifies, + signature_verifies, + } } fn increment_nonce(&self) -> Self::Bool { - todo!() + self.body().increment_nonce } fn use_full_commitment(&self) -> Self::Bool { - todo!() + self.body().use_full_commitment } fn account_precondition_nonce_is_constant(&self, w: &mut Self::W) -> Self::Bool { - todo!() + let nonce = self.body().preconditions.account.nonce(); + nonce.is_constant() } fn implicit_account_creation_fee(&self) -> Self::Bool { - todo!() + self.body().implicit_account_creation_fee } fn balance_change(&self) -> Self::SignedAmount { - todo!() + self.body().balance_change + } +} + +fn controller_check( + proof_verifies: bool, + signature_verifies: bool, + perm: AuthRequired, +) -> Result { + // Invariant: We either have a proof, a signature, or neither. + if proof_verifies && signature_verifies { + return Err("We either have a proof, a signature, or neither.".to_string()); + } + let tag = if proof_verifies { + ControlTag::Proof + } else if signature_verifies { + ControlTag::Signature + } else { + ControlTag::NoneGiven + }; + Ok(check_permission(perm, tag)) +} + +impl ControllerInterface for NonSnarkController { + type W = (); + type Bool = bool; + type SingleData = (); + + fn check( + proof_verifies: Self::Bool, + signature_verifies: Self::Bool, + auth: &AuthRequired, + _single_data: &Self::SingleData, + _w: &mut Self::W, + ) -> Result { + controller_check(proof_verifies, signature_verifies, *auth) + } + + fn verification_key_perm_fallback_to_signature_with_older_version( + auth: &AuthRequired, + w: &mut Self::W, + ) -> AuthRequired { + auth.verification_key_perm_fallback_to_signature_with_older_version() } } -struct NonSnarkBranch; +pub struct NonSnarkBranch; impl BranchInterface for NonSnarkBranch { type W = (); @@ -284,3 +868,172 @@ impl BranchInterface for NonSnarkBranch { BranchEvaluation::Pending(run) } } + +fn get_with_location( + ledger: &L, + account_id: &AccountId, +) -> Result<(ExistingOrNew, Box), String> +where + L: LedgerIntf, +{ + match ledger.location_of_account(account_id) { + Some(location) => match ledger.get(&location) { + Some(account) => Ok((ExistingOrNew::Existing(location), account)), + None => Err("Ledger location with no account".to_string()), + }, + None => Ok(( + ExistingOrNew::New, + Box::new(Account::create_with(account_id.clone(), Balance::zero())), + )), + } +} + +mod ledger { + use super::*; + + type InclusionProof = ExistingOrNew<::Location>; + + pub(super) fn get_account( + ledger: &L, + account_update: &AccountUpdate, + ) -> Result<(Account, InclusionProof), String> { + let (loc, account) = get_with_location(ledger, &account_update.account_id())?; + Ok((*account, loc)) + } + pub(super) fn set_account( + ledger: &mut L, + account: (Account, InclusionProof), + ) -> Result<(), String> { + let (account, location) = account; + set_with_location(ledger, &location, Box::new(account)) + } + pub(super) fn check_account( + public_key: &CompressedPubKey, + token_id: &TokenId, + account: (&Account, &InclusionProof), + ) -> Result { + let (account, loc) = account; + if public_key != &account.public_key { + return Err("check_account: public_key != &account.public_key".to_string()); + } + if token_id != &account.token_id { + return Err("check_account: token_id != &account.token_id".to_string()); + } + match loc { + ExistingOrNew::Existing(_) => Ok(false), + ExistingOrNew::New => Ok(true), + } + } +} + +impl LedgerInterface for Mask { + type W = (); + type AccountUpdate = AccountUpdate; + type Account = Account; + type Bool = bool; + type InclusionProof = ExistingOrNew<::Location>; + + fn empty(depth: usize) -> Self { + ::empty(depth) + } + fn get_account( + &self, + account_update: &Self::AccountUpdate, + _w: &mut Self::W, + ) -> Result<(Self::Account, Self::InclusionProof), String> { + ledger::get_account(self, account_update) + } + fn set_account( + &mut self, + account: (Self::Account, Self::InclusionProof), + _w: &mut Self::W, + ) -> Result<(), String> { + ledger::set_account(self, account) + } + fn check_inclusion(&self, _account: &(Self::Account, Self::InclusionProof), _w: &mut Self::W) { + // Nothing + } + fn check_account( + public_key: &CompressedPubKey, + token_id: &TokenId, + account: (&Self::Account, &Self::InclusionProof), + _w: &mut Self::W, + ) -> Result { + ledger::check_account::(public_key, token_id, account) + } +} +impl LedgerInterface for SparseLedger { + type W = (); + type AccountUpdate = AccountUpdate; + type Account = Account; + type Bool = bool; + type InclusionProof = ExistingOrNew<::Location>; + + fn empty(depth: usize) -> Self { + ::empty(depth) + } + fn get_account( + &self, + account_update: &Self::AccountUpdate, + _w: &mut Self::W, + ) -> Result<(Self::Account, Self::InclusionProof), String> { + ledger::get_account(self, account_update) + } + fn set_account( + &mut self, + account: (Self::Account, Self::InclusionProof), + _w: &mut Self::W, + ) -> Result<(), String> { + ledger::set_account(self, account) + } + fn check_inclusion(&self, _account: &(Self::Account, Self::InclusionProof), _w: &mut Self::W) { + // Nothing + } + fn check_account( + public_key: &CompressedPubKey, + token_id: &TokenId, + account: (&Self::Account, &Self::InclusionProof), + _w: &mut Self::W, + ) -> Result { + ledger::check_account::(public_key, token_id, account) + } +} + +pub fn step( + global_state: &mut GlobalStateForNonSnark, + local_state: &mut zkapp_logic::LocalState>, +) -> Result<(), String> +where + L: LedgerNonSnark, +{ + zkapp_logic::apply( + ApplyZkappParams { + is_start: zkapp_logic::IsStart::No, + global_state, + local_state, + single_data: (), + }, + &mut (), + ) +} + +pub type StartData = StartDataSkeleton, bool>; + +pub fn start( + global_state: &mut GlobalStateForNonSnark, + local_state: &mut zkapp_logic::LocalState>, + start_data: StartData, +) -> Result<(), String> +where + L: LedgerNonSnark, +{ + zkapp_logic::apply( + ApplyZkappParams { + is_start: zkapp_logic::IsStart::Yes(start_data), + global_state, + local_state, + single_data: (), + }, + &mut (), + ) +} diff --git a/ledger/src/zkapps/snark.rs b/ledger/src/zkapps/snark.rs index bcbcc9e25c..49806e3a60 100644 --- a/ledger/src/zkapps/snark.rs +++ b/ledger/src/zkapps/snark.rs @@ -9,7 +9,6 @@ use crate::{ proofs::{ field::{field, Boolean, CircuitVar, FieldWitness, ToBoolean}, numbers::{ - common::ForZkappCheck, currency::{CheckedAmount, CheckedBalance, CheckedCurrency, CheckedSigned}, nat::{CheckedIndex, CheckedNat, CheckedSlot}, }, @@ -32,7 +31,7 @@ use crate::{ ACCOUNT_UPDATE_CONS_HASH_PARAM, }, zkapp_statement::ZkappStatement, - TransactionFailure, + TimingValidation, TransactionFailure, }, }, sparse_ledger::SparseLedger, @@ -41,15 +40,19 @@ use crate::{ ToInputs, TokenId, VerificationKey, VerificationKeyWire, ZkAppAccount, TXN_VERSION_CURRENT, }; -use super::intefaces::{ - AccountIdInterface, AccountInterface, AccountUpdateInterface, ActionsInterface, - AmountInterface, BalanceInterface, BoolInterface, BranchEvaluation, BranchInterface, - BranchParam, CallForestInterface, CallStackInterface, ControllerInterface, - GlobalSlotSinceGenesisInterface, GlobalSlotSpanInterface, GlobalStateInterface, IndexInterface, - LedgerInterface, LocalStateInterface, Opt, ReceiptChainHashInterface, SetOrKeepInterface, - SignedAmountBranchParam, SignedAmountInterface, StackFrameInterface, StackFrameMakeParams, - StackInterface, TokenIdInterface, TransactionCommitmentInterface, TxnVersionInterface, - VerificationKeyHashInterface, WitnessGenerator, ZkappApplication, ZkappHandler, +use super::{ + checks::{InSnarkOps, ZkappCheck}, + intefaces::{ + AccountIdInterface, AccountInterface, AccountUpdateInterface, ActionsInterface, + AmountInterface, BalanceInterface, BoolInterface, BranchEvaluation, BranchInterface, + BranchParam, CallForestInterface, CallStackInterface, ControllerInterface, + GlobalSlotSinceGenesisInterface, GlobalSlotSpanInterface, GlobalStateInterface, + IndexInterface, LedgerInterface, LocalStateInterface, Opt, ReceiptChainHashInterface, + SetOrKeepInterface, SignedAmountBranchParam, SignedAmountInterface, StackFrameInterface, + StackFrameMakeParams, StackInterface, TokenIdInterface, TransactionCommitmentInterface, + TxnVersionInterface, VerificationKeyHashInterface, WitnessGenerator, ZkappApplication, + ZkappHandler, + }, }; pub struct ZkappSnark; @@ -87,96 +90,6 @@ impl ZkappApplication for ZkappSnark { type WitnessGenerator = Witness; } -pub mod zkapp_check { - use super::*; - - pub trait InSnarkCheck { - type T; - - fn checked_zcheck(&self, x: &Self::T, w: &mut Witness) -> Boolean; - } - - impl OrIgnore { - fn make_zcheck(&self, default_fn: F, compare_fun: F2, w: &mut Witness) -> Boolean - where - F: Fn() -> T, - F2: Fn(&T, &mut Witness) -> Boolean, - { - let (is_some, value) = match self { - OrIgnore::Check(v) => (Boolean::True, MyCow::Borrow(v)), - OrIgnore::Ignore => (Boolean::False, MyCow::Own(default_fn())), - }; - let is_good = compare_fun(&*value, w); - Boolean::any(&[is_some.neg(), is_good], w) - } - } - - impl InSnarkCheck for (&OrIgnore, Fun) - where - Fun: Fn() -> Boolean, - { - type T = Boolean; - - fn checked_zcheck(&self, x: &Self::T, w: &mut Witness) -> Boolean { - let (this, default_fn) = self; - let compare = |value: &Self::T, w: &mut Witness| Boolean::equal(x, value, w); - this.make_zcheck(default_fn, compare, w) - } - } - - impl InSnarkCheck for (&OrIgnore, Fun) - where - Fun: Fn() -> Fp, - { - type T = Fp; - - fn checked_zcheck(&self, x: &Self::T, w: &mut Witness) -> Boolean { - let (this, default_fn) = self; - let compare = |value: &Self::T, w: &mut Witness| field::equal(*x, *value, w); - this.make_zcheck(default_fn, compare, w) - } - } - - impl InSnarkCheck for (&OrIgnore, Fun) - where - Fun: Fn() -> CompressedPubKey, - { - type T = CompressedPubKey; - - fn checked_zcheck(&self, x: &Self::T, w: &mut Witness) -> Boolean { - let (this, default_fn) = self; - let compare = |value: &Self::T, w: &mut Witness| { - checked_equal_compressed_key(x, value, w) - // checked_equal_compressed_key_const_and(x, value, w) - }; - this.make_zcheck(default_fn, compare, w) - } - } - - impl InSnarkCheck for (&OrIgnore>, Fun) - where - Fun: Fn() -> ClosedInterval, - T: ForZkappCheck, - { - type T = T; - - fn checked_zcheck(&self, x: &Self::T, w: &mut Witness) -> Boolean { - let (this, default_fn) = self; - let compare = |value: &ClosedInterval, w: &mut Witness| { - let ClosedInterval { lower, upper } = value; - let lower = lower.to_checked(); - let upper = upper.to_checked(); - let x = x.to_checked(); - // We decompose this way because of OCaml evaluation order - let lower_than_upper = >::lte(&x, &upper, w); - let greater_than_lower = >::lte(&lower, &x, w); - Boolean::all(&[greater_than_lower, lower_than_upper], w) - }; - this.make_zcheck(default_fn, compare, w) - } - } -} - impl WitnessGenerator for Witness { type Bool = SnarkBool; @@ -223,12 +136,11 @@ impl ZkappHandler for SnarkHandler { let check = |failure: TransactionFailure, b: Boolean, w: &mut Witness| { zkapp_logic::LocalState::::add_check(local_state, failure, b.var(), w); }; - account_update.body.preconditions.account.checked_zcheck( - new_account.as_boolean(), - &account.data, - check, - w, - ); + account_update + .body + .preconditions + .account + .zcheck::(new_account.as_boolean(), &account.data, check, w); } fn check_protocol_state_precondition( @@ -237,7 +149,7 @@ impl ZkappHandler for SnarkHandler { w: &mut Self::W, ) -> Self::Bool { protocol_state_predicate - .checked_zcheck(&global_state.protocol_state, w) + .zcheck::(&global_state.protocol_state, w) .var() } @@ -246,17 +158,12 @@ impl ZkappHandler for SnarkHandler { global_state: &mut Self::GlobalState, w: &mut Self::W, ) -> Self::Bool { - use zkapp_check::InSnarkCheck; - (valid_while, ClosedInterval::min_max) - .checked_zcheck(&global_state.block_global_slot.to_inner(), w) + .zcheck::(&global_state.block_global_slot.to_inner(), w) .var() } - fn init_account( - account_update: &Self::AccountUpdate, - account: &Self::Account, - ) -> Self::Account { + fn init_account(account_update: &Self::AccountUpdate, account: Self::Account) -> Self::Account { let AccountUpdateSkeleton { body: account_update, authorization: _, @@ -264,7 +171,7 @@ impl ZkappHandler for SnarkHandler { let account = Box::new(crate::Account { public_key: account_update.data.public_key.clone(), token_id: account_update.data.token_id.clone(), - ..(*account.data).clone() + ..*account.data }); let account2 = account.clone(); let account = WithLazyHash::new(account, move |w: &mut Witness| { @@ -655,6 +562,10 @@ impl GlobalSlotSinceGenesisInterface for SnarkGlobalSlot { fn equal(&self, other: &Self, w: &mut Self::W) -> Self::Bool { >::equal(self, other, w).var() } + + fn exists_no_check(self, w: &mut Self::W) -> Self { + w.exists_no_check(self) + } } fn signature_verifies( @@ -678,6 +589,7 @@ impl AccountUpdateInterface for SnarkAccountUpdate { type SingleData = ZkappSingleData; type Bool = SnarkBool; type SignedAmount = SnarkSignedAmount; + type VerificationKeyHash = SnarkVerificationKeyHash; fn body(&self) -> &crate::scan_state::transaction_logic::zkapp_command::Body { let Self { @@ -687,12 +599,6 @@ impl AccountUpdateInterface for SnarkAccountUpdate { let WithHash { data, hash: _ } = body; data } - fn set(&mut self, new: Self) { - *self = new; - } - fn verification_key_hash(&self) -> Fp { - self.body().authorization_kind.vk_hash() - } fn is_proved(&self) -> Self::Bool { self.body() .authorization_kind @@ -707,6 +613,10 @@ impl AccountUpdateInterface for SnarkAccountUpdate { .to_boolean() .var() } + fn verification_key_hash(&self) -> Self::VerificationKeyHash { + let hash = self.body().authorization_kind.vk_hash(); + SnarkVerificationKeyHash(hash) + } fn check_authorization( &self, will_succeed: Self::Bool, @@ -937,6 +847,7 @@ impl AccountInterface for SnarkAccount { type Bool = SnarkBool; type Balance = SnarkBalance; type GlobalSlot = SnarkGlobalSlot; + type VerificationKeyHash = SnarkVerificationKeyHash; fn register_verification_key(&self, data: &Self::D, w: &mut Self::W) { use crate::ControlTag::*; @@ -982,13 +893,14 @@ impl AccountInterface for SnarkAccount { // `unwrap`: `make_zkapp` is supposed to be called before `zkapp_mut` self.data.zkapp.as_mut().unwrap() } - fn verification_key_hash(&self) -> Fp { + fn verification_key_hash(&self) -> Self::VerificationKeyHash { let zkapp = self.zkapp(); - zkapp + let hash = zkapp .verification_key .as_ref() .map(VerificationKeyWire::hash) - .unwrap_or_else(VerificationKeyWire::dummy_hash) + .unwrap_or_else(VerificationKeyWire::dummy_hash); + SnarkVerificationKeyHash(hash) } fn set_token_id(&mut self, token_id: TokenId) { let Self { data: account, .. } = self; @@ -1009,7 +921,7 @@ impl AccountInterface for SnarkAccount { &self, txn_global_slot: &Self::GlobalSlot, w: &mut Self::W, - ) -> (Self::Bool, crate::Timing) { + ) -> (TimingValidation, crate::Timing) { let mut invalid_timing = Option::::None; let timed_balance_check = |b: Boolean, _w: &mut Witness| { invalid_timing = Some(b.neg()); @@ -1017,7 +929,10 @@ impl AccountInterface for SnarkAccount { let account = self.get(); let (_min_balance, timing) = check_timing(account, None, *txn_global_slot, timed_balance_check, w); - (invalid_timing.unwrap().var(), timing) + ( + TimingValidation::InvalidTiming(invalid_timing.unwrap().var()), + timing, + ) } fn make_zkapp(&mut self) { if self.data.zkapp.is_none() { @@ -1077,8 +992,8 @@ impl LedgerInterface for LedgerWithHash { type Bool = SnarkBool; type InclusionProof = Vec<(Boolean, Fp)>; - fn empty() -> Self { - let mut ledger = ::empty(0); + fn empty(depth: usize) -> Self { + let mut ledger = ::empty(depth); let hash = ledger.merkle_root(); Self { ledger, hash } } @@ -1086,7 +1001,7 @@ impl LedgerInterface for LedgerWithHash { &self, account_update: &Self::AccountUpdate, w: &mut Self::W, - ) -> (Self::Account, Self::InclusionProof) { + ) -> Result<(Self::Account, Self::InclusionProof), String> { let Self { ledger, hash: _root, @@ -1111,14 +1026,19 @@ impl LedgerInterface for LedgerWithHash { }) .collect::>(), ); - (account, inclusion) + Ok((account, inclusion)) } - fn set_account(&mut self, (a, incl): (Self::Account, Self::InclusionProof), w: &mut Self::W) { + fn set_account( + &mut self, + (a, incl): (Self::Account, Self::InclusionProof), + w: &mut Self::W, + ) -> Result<(), String> { let Self { ledger, hash } = self; let new_hash = implied_root(&a, &incl, w); let idx = ledger.find_index_exn(a.id()); ledger.set_exn(idx, a.data); *hash = new_hash; + Ok(()) } fn check_inclusion( &self, @@ -1132,7 +1052,7 @@ impl LedgerInterface for LedgerWithHash { token_id: &TokenId, account: (&Self::Account, &Self::InclusionProof), w: &mut Self::W, - ) -> Self::Bool { + ) -> Result { let (WithLazyHash { data: account, .. }, _) = account; let is_new = checked_equal_compressed_key_const_and( &account.public_key, @@ -1143,7 +1063,7 @@ impl LedgerInterface for LedgerWithHash { Boolean::assert_any(&[is_new, is_same], w); let is_same_token = field::equal(token_id.0, account.token_id.0, w); Boolean::assert_any(&[is_new, is_same_token], w); - is_new.var() + Ok(is_new.var()) } fn exists_no_check(self, w: &mut Self::W) -> Self { w.exists_no_check(self.hash); @@ -1162,7 +1082,7 @@ pub type SnarkAmount = CheckedAmount; pub type SnarkSignedAmount = CheckedSigned>; pub type SnarkBalance = CheckedBalance; pub struct SnarkTransactionCommitment; -pub struct SnarkVerificationKeyHash; +pub struct SnarkVerificationKeyHash(Fp); pub struct SnarkController; pub struct SnarkTxnVersion; pub struct SnarkSetOrKeep; @@ -1192,8 +1112,10 @@ impl VerificationKeyHashInterface for SnarkVerificationKeyHash { type W = Witness; type Bool = SnarkBool; - fn equal(a: Fp, b: Fp, w: &mut Self::W) -> Self::Bool { - field::equal(a, b, w).var() + fn equal(a: &Self, b: &Self, w: &mut Self::W) -> Self::Bool { + let Self(a) = a; + let Self(b) = b; + field::equal(*a, *b, w).var() } } @@ -1228,8 +1150,9 @@ impl BoolInterface for SnarkBool { fn all(bs: &[Self], w: &mut Self::W) -> Self { SnarkBool::all(bs, w) } - fn assert_any(bs: &[Self], w: &mut Self::W) { + fn assert_any(bs: &[Self], w: &mut Self::W) -> Result<(), String> { SnarkBool::assert_any::(bs, w); + Ok(()) } fn assert_with_failure_status_tbl( _b: Self, @@ -1356,13 +1279,13 @@ impl ControllerInterface for SnarkController { auth: &AuthRequired, single_data: &Self::SingleData, w: &mut Self::W, - ) -> Self::Bool { + ) -> Result { use crate::ControlTag::{NoneGiven, Proof, Signature}; - match single_data.spec().auth_type { + Ok(match single_data.spec().auth_type { Proof => eval_proof(auth, w), Signature | NoneGiven => eval_no_proof(auth, signature_verifies, w), - } + }) } fn verification_key_perm_fallback_to_signature_with_older_version( diff --git a/ledger/src/zkapps/zkapp_logic.rs b/ledger/src/zkapps/zkapp_logic.rs index d8423111bc..bde54a57dd 100644 --- a/ledger/src/zkapps/zkapp_logic.rs +++ b/ledger/src/zkapps/zkapp_logic.rs @@ -3,6 +3,7 @@ use mina_signer::CompressedPubKey; use openmina_core::constants::constraint_constants; use crate::scan_state::transaction_logic::zkapp_command::{Actions, SetOrKeep}; +use crate::scan_state::transaction_logic::TimingValidation; use crate::{ scan_state::{ currency::{Fee, Magnitude, SlotSpan}, @@ -27,12 +28,6 @@ pub enum IsStart { Compute(T), } -enum PerformResult { - None, - Bool(Z::Bool), - Account(Z::Account), -} - struct GetNextAccountUpdateResult { account_update: Z::AccountUpdate, caller_id: TokenId, @@ -41,6 +36,11 @@ struct GetNextAccountUpdateResult { new_frame: Z::StackFrame, } +#[derive(Clone)] +pub enum ZkAppCommandElt { + ZkAppCommandCommitment(crate::ReceiptChainHash), +} + fn assert_(_b: Z::Bool) -> Result<(), String> { // Used only for circuit generation (add constraints) // https://github.com/MinaProtocol/mina/blob/e44ddfe1ca54b3855e1ed336d89f6230d35aeb8c/src/lib/transaction_logic/zkapp_command_logic.ml#L929 @@ -256,7 +256,7 @@ fn get_next_account_update( } } -fn update_action_state( +pub fn update_action_state( action_state: &[Fp; 5], actions: &Actions, txn_global_slot: Z::GlobalSlotSinceGenesis, @@ -289,10 +289,11 @@ fn update_action_state( Boolean::True => s2, Boolean::False => s1, }); - let last_action_slot = w.exists_no_check(match is_empty.as_boolean() { + let last_action_slot = match is_empty.as_boolean() { Boolean::True => last_action_slot, Boolean::False => txn_global_slot, - }); + } + .exists_no_check(w); ([s1_new, s2, s3, s4, s5], last_action_slot) } @@ -365,13 +366,11 @@ where IsStart::Yes(start_data) => start_data.will_succeed, IsStart::No => local_state.will_succeed, }; - local_state.ledger = w.exists_no_check_on_bool( - is_start2, - match is_start2.as_boolean() { - Boolean::True => global_state.first_pass_ledger(), - Boolean::False => local_state.ledger.clone(), - }, - ); + local_state.ledger = match is_start2.as_boolean() { + Boolean::True => global_state.first_pass_ledger(), + Boolean::False => local_state.ledger.clone(), + } + .exists_no_check_on_bool(is_start2, w); local_state.will_succeed = will_succeed; let ((account_update, remaining, call_stack), account_update_forest, (mut a, inclusion_proof)) = { @@ -438,7 +437,7 @@ where ); }; - let acct = local_state.ledger.get_account(&account_update, w); + let acct = local_state.ledger.get_account(&account_update, w)?; local_state.ledger.check_inclusion(&acct, w); let (transaction_commitment, full_transaction_commitment) = match is_start { @@ -488,7 +487,7 @@ where &account_update.body().token_id, (&a, &inclusion_proof), w, - ); + )?; { let self_delegate = { @@ -512,8 +511,8 @@ where let matching_verification_key_hashes = { let is_not_proved = account_update.is_proved().neg(); let is_same_vk = Z::VerificationKeyHash::equal( - a.verification_key_hash(), - account_update.verification_key_hash(), + &a.verification_key_hash(), + &account_update.verification_key_hash(), w, ); Z::Bool::or(is_not_proved, is_same_vk, w) @@ -635,7 +634,7 @@ where set_timing, &single_data, w, - ) + )? }; let is_keep = Z::SetOrKeep::is_keep(timing); let v_and = Z::Bool::and(account_is_untimed, has_permission, w); @@ -778,7 +777,7 @@ where &controller, &single_data, w, - ); + )?; let first = Z::SignedAmount::equal(&Z::SignedAmount::zero(), &actual_balance_change, w); Z::LocalState::add_check( local_state, @@ -794,7 +793,12 @@ where let txn_global_slot = global_state.block_global_slot(); // Check timing with current balance let (_a, _local_state) = { - let (invalid_timing, timing) = Z::Account::check_timing(&a, &txn_global_slot, w); + let (invalid_timing, timing) = match Z::Account::check_timing(&a, &txn_global_slot, w) { + (TimingValidation::InsufficientBalance(_), _) => { + return Err("Did not propose a balance change at this timing check!".to_string()) + } + (TimingValidation::InvalidTiming(invalid_timing), timing) => (invalid_timing, timing), + }; Z::LocalState::add_check( local_state, TransactionFailure::SourceMinimumBalanceViolation, @@ -810,7 +814,7 @@ where { let has_permission = { let access = &a.get().permissions.access; - Z::Controller::check(proof_verifies, signature_verifies, access, &single_data, w) + Z::Controller::check(proof_verifies, signature_verifies, access, &single_data, w)? }; Z::LocalState::add_check( local_state, @@ -861,7 +865,7 @@ where edit_state, &single_data, w, - ) + )? }; Z::LocalState::add_check( local_state, @@ -914,7 +918,7 @@ where ) }; - Z::Controller::check(proof_verifies, signature_verifies, &auth, &single_data, w) + Z::Controller::check(proof_verifies, signature_verifies, &auth, &single_data, w)? }; Z::LocalState::add_check( local_state, @@ -960,7 +964,7 @@ where edit_action_state, &single_data, w, - ) + )? }; Z::LocalState::add_check( local_state, @@ -984,7 +988,7 @@ where set_zkapp_uri, &single_data, w, - ) + )? }; Z::LocalState::add_check( local_state, @@ -1014,7 +1018,7 @@ where set_token_symbol, &single_data, w, - ) + )? }; Z::LocalState::add_check( local_state, @@ -1043,7 +1047,7 @@ where set_delegate, &single_data, w, - ) + )? }; let first = Z::Bool::and(has_permission, account_update_token_is_default, w); Z::LocalState::add_check( @@ -1081,7 +1085,7 @@ where increment_nonce, &single_data, w, - ) + )? }; Z::LocalState::add_check( local_state, @@ -1104,7 +1108,7 @@ where set_voting_for, &single_data, w, - ) + )? }; Z::LocalState::add_check( local_state, @@ -1151,7 +1155,7 @@ where set_permissions, &single_data, w, - ) + )? }; Z::LocalState::add_check( local_state, @@ -1170,7 +1174,7 @@ where ((), ()) }; - let a = Z::Handler::init_account(&account_update, &a); + let a = Z::Handler::init_account(&account_update, a); let local_delta = account_update_balance_change.negate(); @@ -1204,7 +1208,7 @@ where overflowed.neg(), w, ); - local_state.ledger.set_account((a, inclusion_proof), w); + local_state.ledger.set_account((a, inclusion_proof), w)?; let is_last_account_update = Z::CallForest::is_empty(Z::StackFrame::calls(&remaining), w); // We decompose this way because of OCaml evaluation order @@ -1307,7 +1311,7 @@ where local_state.success.neg(), ], w, - ); + )?; // global state { @@ -1340,7 +1344,7 @@ where Boolean::False => local_state.success, }); let ledger = match is_last_account_update.as_boolean() { - Boolean::True => Z::Ledger::empty(), + Boolean::True => Z::Ledger::empty(0), Boolean::False => local_state.ledger.clone(), } .exists_no_check(w); diff --git a/macros/Cargo.toml b/macros/Cargo.toml index ea153d0478..fa55f22393 100644 --- a/macros/Cargo.toml +++ b/macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openmina-macros" -version = "0.9.0" +version = "0.10.0" edition = "2021" license = "Apache-2.0" authors = [ "Alexander Koptelov " ] diff --git a/mina-p2p-messages/Cargo.toml b/mina-p2p-messages/Cargo.toml index 6bc3bb7bb6..760edce55e 100644 --- a/mina-p2p-messages/Cargo.toml +++ b/mina-p2p-messages/Cargo.toml @@ -21,6 +21,9 @@ sha2 = { version = "0.10.2" } blake2 = { version = "0.10" } time = "0.3.36" num-bigint = "0.4.6" +strum = "0.26.2" +strum_macros = "0.26.4" +lazy_static = "1.4.0" openmina-macros = { path = "../macros" } diff --git a/mina-p2p-messages/src/bigint.rs b/mina-p2p-messages/src/bigint.rs index 4ff1247b0e..4f1d093d18 100644 --- a/mina-p2p-messages/src/bigint.rs +++ b/mina-p2p-messages/src/bigint.rs @@ -13,6 +13,10 @@ impl std::fmt::Debug for BigInt { } } +#[derive(Debug, thiserror::Error)] +#[error("Invalid decimal number")] +pub struct InvalidDecimalNumber; + impl BigInt { pub fn zero() -> Self { mina_curves::pasta::Fp::from(0u64).into() @@ -41,6 +45,22 @@ impl BigInt { use ark_ff::FromBytes; Self(BigInteger256::read(&bytes[..]).unwrap()) // Never fail, we read from 32 bytes } + + pub fn from_decimal(s: &str) -> Result { + num_bigint::BigInt::parse_bytes(s.as_bytes(), 10) + .map(|num| { + let mut bytes = num.to_bytes_be().1; + bytes.reverse(); + bytes.resize(32, 0); // Ensure the byte vector has 32 bytes + BigInt::from_bytes(bytes.try_into().unwrap()) + }) + .ok_or(InvalidDecimalNumber) + } + + pub fn to_decimal(&self) -> String { + let bigint: num_bigint::BigUint = self.0.into(); + bigint.to_string() + } } impl AsRef for BigInt { diff --git a/core/src/dummy/dummy_blockchain_proof.bin b/mina-p2p-messages/src/v2/dummy/dummy_blockchain_proof.bin similarity index 100% rename from core/src/dummy/dummy_blockchain_proof.bin rename to mina-p2p-messages/src/v2/dummy/dummy_blockchain_proof.bin diff --git a/core/src/dummy/dummy_transaction_proof.bin b/mina-p2p-messages/src/v2/dummy/dummy_transaction_proof.bin similarity index 100% rename from core/src/dummy/dummy_transaction_proof.bin rename to mina-p2p-messages/src/v2/dummy/dummy_transaction_proof.bin diff --git a/mina-p2p-messages/src/v2/dummy/mod.rs b/mina-p2p-messages/src/v2/dummy/mod.rs new file mode 100644 index 0000000000..9b28c0f3fb --- /dev/null +++ b/mina-p2p-messages/src/v2/dummy/mod.rs @@ -0,0 +1,60 @@ +use std::sync::Arc; + +use binprot::BinProtRead; + +use super::{MinaBaseProofStableV2, TransactionSnarkProofStableV2}; + +/// Value of `Proof.transaction_dummy` when we run `dune runtest src/lib/staged_ledger -f` +/// The file was generated this way: +/// +/// let dummy = Proof.transaction_dummy in +/// +/// let buf = Bigstring.create (Proof.Stable.V2.bin_size_t dummy) in +/// ignore (Proof.Stable.V2.bin_write_t buf ~pos:0 dummy : int) ; +/// let bytes = Bigstring.to_bytes buf in +/// +/// let explode s = List.init (String.length s) ~f:(fun i -> String.get s i) in +/// +/// let s = (String.concat ~sep:"," (List.map (explode (Bytes.to_string bytes)) ~f:(fun b -> string_of_int (Char.to_int b)))) in +/// +/// Core.Printf.eprintf !"dummy proof= %{sexp: Proof.t}\n%!" dummy; +/// Core.Printf.eprintf !"dummy proof= %s\n%!" s; +pub fn dummy_transaction_proof() -> Arc { + lazy_static::lazy_static! { + static ref DUMMY_PROOF: Arc = { + let bytes = include_bytes!("dummy_transaction_proof.bin"); + TransactionSnarkProofStableV2::binprot_read(&mut bytes.as_slice()) + .unwrap() + .into() + }; + } + + DUMMY_PROOF.clone() +} + +pub fn sideloaded_transaction_proof() -> Arc { + lazy_static::lazy_static! { + static ref DUMMY_PROOF: Arc = { + let bytes = include_bytes!("sideloaded_proof.bin"); + TransactionSnarkProofStableV2::binprot_read(&mut bytes.as_slice()) + .unwrap() + .into() + }; + } + + DUMMY_PROOF.clone() +} + +/// Value of `Proof.blockchain_dummy` +pub fn dummy_blockchain_proof() -> Arc { + lazy_static::lazy_static! { + static ref DUMMY_PROOF: Arc = { + let bytes = include_bytes!("dummy_blockchain_proof.bin"); + MinaBaseProofStableV2::binprot_read(&mut bytes.as_slice()) + .unwrap() + .into() + }; + } + + DUMMY_PROOF.clone() +} diff --git a/mina-p2p-messages/src/v2/dummy/sideloaded_proof.bin b/mina-p2p-messages/src/v2/dummy/sideloaded_proof.bin new file mode 100644 index 0000000000..6f6759f3fe Binary files /dev/null and b/mina-p2p-messages/src/v2/dummy/sideloaded_proof.bin differ diff --git a/mina-p2p-messages/src/v2/generated.rs b/mina-p2p-messages/src/v2/generated.rs index e83271db66..866c3f22ce 100644 --- a/mina-p2p-messages/src/v2/generated.rs +++ b/mina-p2p-messages/src/v2/generated.rs @@ -1225,7 +1225,16 @@ pub struct MinaBaseLedgerHash0StableV1(pub crate::bigint::BigInt); /// /// Gid: `706` /// Location: [src/lib/mina_base/permissions.ml:53:6](https://github.com/MinaProtocol/mina/blob/1551e2faaa/src/lib/mina_base/permissions.ml#L53) -#[derive(Clone, Debug, PartialEq, SerdeYojsonEnum, BinProtRead, BinProtWrite)] +#[derive( + Clone, + Debug, + PartialEq, + SerdeYojsonEnum, + BinProtRead, + BinProtWrite, + strum_macros::Display, + strum_macros::EnumString, +)] pub enum MinaBasePermissionsAuthRequiredStableV2 { None, Either, @@ -1276,7 +1285,9 @@ pub enum MinaBaseStakeDelegationStableV2 { /// /// Gid: `718` /// Location: [src/lib/mina_base/transaction_status.ml:9:6](https://github.com/MinaProtocol/mina/blob/1551e2faaa/src/lib/mina_base/transaction_status.ml#L9) -#[derive(Clone, Debug, PartialEq, SerdeYojsonEnum, BinProtRead, BinProtWrite)] +#[derive( + Clone, Debug, PartialEq, SerdeYojsonEnum, BinProtRead, BinProtWrite, strum_macros::Display, +)] pub enum MinaBaseTransactionStatusFailureStableV2 { Predicate, SourceNotPresent, diff --git a/mina-p2p-messages/src/v2/hashing.rs b/mina-p2p-messages/src/v2/hashing.rs index 47f37b2ff3..71137d49b4 100644 --- a/mina-p2p-messages/src/v2/hashing.rs +++ b/mina-p2p-messages/src/v2/hashing.rs @@ -28,11 +28,12 @@ use super::{ ConsensusProofOfStakeDataEpochDataNextValueVersionedValueStableV1, ConsensusProofOfStakeDataEpochDataStakingValueVersionedValueStableV1, ConsensusVrfOutputTruncatedStableV1, DataHashLibStateHashStableV1, LedgerHash, - MinaBaseEpochLedgerValueStableV1, MinaBaseFeeExcessStableV1, MinaBaseLedgerHash0StableV1, - MinaBasePendingCoinbaseHashBuilderStableV1, MinaBasePendingCoinbaseHashVersionedStableV1, - MinaBasePendingCoinbaseStackVersionedStableV1, MinaBasePendingCoinbaseStateStackStableV1, - MinaBaseProtocolConstantsCheckedValueStableV1, MinaBaseStagedLedgerHashNonSnarkStableV1, - MinaBaseStagedLedgerHashStableV1, MinaBaseStateBodyHashStableV1, + MinaBaseControlStableV2, MinaBaseEpochLedgerValueStableV1, MinaBaseFeeExcessStableV1, + MinaBaseLedgerHash0StableV1, MinaBasePendingCoinbaseHashBuilderStableV1, + MinaBasePendingCoinbaseHashVersionedStableV1, MinaBasePendingCoinbaseStackVersionedStableV1, + MinaBasePendingCoinbaseStateStackStableV1, MinaBaseProtocolConstantsCheckedValueStableV1, + MinaBaseStagedLedgerHashNonSnarkStableV1, MinaBaseStagedLedgerHashStableV1, + MinaBaseStateBodyHashStableV1, MinaBaseZkappCommandTStableV1WireStableV1AccountUpdatesAA, MinaNumbersGlobalSlotSinceGenesisMStableV1, MinaNumbersGlobalSlotSinceHardForkMStableV1, MinaNumbersGlobalSlotSpanStableV1, MinaStateBlockchainStateValueStableV2LedgerProofStatement, MinaStateBlockchainStateValueStableV2LedgerProofStatementSource, @@ -184,12 +185,69 @@ impl generated::MinaBaseSignedCommandStableV2 { } } +// TODO(adonagy): reduce duplication impl generated::MinaBaseZkappCommandTStableV1WireStableV1 { + fn binprot_write_with_default(&self) -> io::Result> { + let default_signature = generated::MinaBaseSignatureStableV1(BigInt::one(), BigInt::one()); + + let mut encoded = vec![]; + + let mut modified = self.clone(); + + modified.fee_payer.authorization = default_signature.clone().into(); + + modified.account_updates.iter_mut().for_each(|u| { + Self::replace_auth_recursive(&mut u.elt); + }); + + modified.binprot_write(&mut encoded)?; + Ok(encoded) + } + + fn replace_auth_recursive( + update_elt: &mut MinaBaseZkappCommandTStableV1WireStableV1AccountUpdatesAA, + ) { + Self::replace_auth(&mut update_elt.account_update.authorization); + // if update_elt.calls.is_empty() { + // return; + // } + + update_elt.calls.iter_mut().for_each(|call| { + Self::replace_auth_recursive(&mut call.elt); + }); + + // for call in update_elt.calls.iter_mut() { + // Self::replace_auth_recursive(&mut call.elt); + // } + } + + pub fn replace_auth(auth: &mut MinaBaseControlStableV2) { + let default_signature = generated::MinaBaseSignatureStableV1(BigInt::one(), BigInt::one()); + let default_proof = super::dummy_transaction_proof(); + *auth = match auth { + MinaBaseControlStableV2::Proof(_) => { + MinaBaseControlStableV2::Proof(Box::new(default_proof.0.clone().into())) + } + MinaBaseControlStableV2::Signature(_) => { + MinaBaseControlStableV2::Signature(default_signature.clone().into()) + } + MinaBaseControlStableV2::NoneGiven => MinaBaseControlStableV2::NoneGiven, + }; + } + pub fn hash(&self) -> io::Result { - Err(io::Error::new( - io::ErrorKind::Unsupported, - "zkapp tx hashing is not yet supported", - )) + use blake2::{ + digest::{Update, VariableOutput}, + Blake2bVar, + }; + let mut hasher = Blake2bVar::new(32).expect("Invalid Blake2bVar output size"); + + hasher.update(&self.binprot_write_with_default()?); + let mut hash = vec![0; 33]; + hash[..1].copy_from_slice(&[32]); + hash[1..].copy_from_slice(&hasher.finalize_boxed()); + + Ok(TransactionHash(hash)) } } @@ -788,7 +846,11 @@ impl ToInput for MinaNumbersGlobalSlotSpanStableV1 { #[cfg(test)] mod hash_tests { - use crate::v2::MinaStateProtocolStateValueStableV2; + use binprot::BinProtRead; + + use crate::v2::{ + MinaBaseZkappCommandTStableV1WireStableV1, MinaStateProtocolStateValueStableV2, + }; #[test] #[ignore = "fix expected hash/hasing"] @@ -801,4 +863,30 @@ mod hash_tests { let expected_hash = serde_json::from_value(serde_json::json!(HASH)).unwrap(); assert_eq!(hash, expected_hash) } + + #[test] + fn test_zkapp_with_proof_auth_hash() { + // expected: 5JtkEP5AugQKKQAk3YKFxxUDggWf8AiAYyCQy49t2kLHRgPqcP8o + // MinaBaseZkappCommandTStableV1WireStableV1 + // + let expected_hash = "5JtkEP5AugQKKQAk3YKFxxUDggWf8AiAYyCQy49t2kLHRgPqcP8o".to_string(); + let bytes = include_bytes!("../../../tests/files/zkapps/with_proof_auth.bin"); + let zkapp = + MinaBaseZkappCommandTStableV1WireStableV1::binprot_read(&mut bytes.as_slice()).unwrap(); + let hash = zkapp.hash().unwrap().to_string(); + + assert_eq!(expected_hash, hash); + } + + #[test] + + fn test_zkapp_with_sig_auth_hash() { + let expected_hash = "5JvQ6xQeGgCTe2d4KpCsJ97yK61mNRZHixJxPbKTppY1qSGgtj6t".to_string(); + let bytes = include_bytes!("../../../tests/files/zkapps/with_sig_auth.bin"); + let zkapp = + MinaBaseZkappCommandTStableV1WireStableV1::binprot_read(&mut bytes.as_slice()).unwrap(); + let hash = zkapp.hash().unwrap().to_string(); + + assert_eq!(expected_hash, hash); + } } diff --git a/mina-p2p-messages/src/v2/manual.rs b/mina-p2p-messages/src/v2/manual.rs index e7b2de379e..de8e4c8c3a 100644 --- a/mina-p2p-messages/src/v2/manual.rs +++ b/mina-p2p-messages/src/v2/manual.rs @@ -43,6 +43,17 @@ pub type TransactionSnarkScanStateStableV2TreesAMerge = ( #[derive(Clone, Debug, PartialEq, BinProtRead, BinProtWrite, Deref)] pub struct MinaBaseSignedCommandMemoStableV1(pub crate::string::CharString); +impl MinaBaseSignedCommandMemoStableV1 { + pub fn to_base58check(&self) -> String { + b58::encode(self.0.as_ref(), USER_COMMAND_MEMO) + } + + pub fn from_base58check(s: &str) -> Self { + let decoded = b58::decode(s, USER_COMMAND_MEMO).unwrap(); + MinaBaseSignedCommandMemoStableV1(decoded[1..].into()) + } +} + impl Serialize for MinaBaseSignedCommandMemoStableV1 { fn serialize(&self, serializer: S) -> Result where @@ -491,6 +502,11 @@ base58check_of_binprot!( versioned MinaBasePendingCoinbaseHashVersionedStableV1, RECEIPT_CHAIN_HASH ); +base58check_of_binprot!( + ReceiptChainHash, + versioned MinaBaseReceiptChainHashStableV1, + RECEIPT_CHAIN_HASH +); base58check_of_binprot!( TokenIdKeyHash, MinaBaseAccountIdDigestStableV1, @@ -949,6 +965,70 @@ impl<'de> Deserialize<'de> for ConsensusVrfOutputTruncatedStableV1 { } } +impl MinaBaseVerificationKeyWireStableV1 { + pub fn to_base64(&self) -> Result { + let mut buffer: Vec = Vec::new(); + self.binprot_write(&mut buffer)?; + use base64::{engine::general_purpose::STANDARD, Engine as _}; + + let base64_data = STANDARD.encode(buffer); + Ok(base64_data) + } + + pub fn from_base64(base64_data: &str) -> Result { + use base64::{engine::general_purpose::STANDARD, Engine as _}; + let decoded_data = STANDARD.decode(base64_data)?; + let res = MinaBaseVerificationKeyWireStableV1::binprot_read(&mut decoded_data.as_slice())?; + Ok(res) + } +} + +// TODO(adonagy): macro? +impl MinaBaseSignedCommandStableV2 { + pub fn to_base64(&self) -> Result { + const COMMAND_VERSION_TAG: u8 = 2; + + let mut buffer: Vec = Vec::new(); + COMMAND_VERSION_TAG.binprot_write(&mut buffer)?; + self.binprot_write(&mut buffer)?; + use base64::{engine::general_purpose::STANDARD, Engine as _}; + + let base64_data = STANDARD.encode(buffer); + Ok(base64_data) + } + + pub fn from_base64(base64_data: &str) -> Result { + use base64::{engine::general_purpose::STANDARD, Engine as _}; + let decoded_data = STANDARD.decode(&base64_data)?; + let res = MinaBaseSignedCommandStableV2::binprot_read(&mut decoded_data[1..].as_ref())?; + Ok(res) + } +} + +/// TODO(adonagy): implement the base64 conversions similarly to the base58check ones (versioned/not versioned) +impl MinaBaseZkappCommandTStableV1WireStableV1 { + pub fn to_base64(&self) -> Result { + const ZKAPP_VERSION_TAG: u8 = 1; + + let mut buffer: Vec = Vec::new(); + ZKAPP_VERSION_TAG.binprot_write(&mut buffer)?; + self.binprot_write(&mut buffer)?; + use base64::{engine::general_purpose::STANDARD, Engine as _}; + + let base64_data = STANDARD.encode(buffer); + Ok(base64_data) + } + + pub fn from_base64(base64_data: &str) -> Result { + use base64::{engine::general_purpose::STANDARD, Engine as _}; + let decoded_data = STANDARD.decode(&base64_data)?; + let res = MinaBaseZkappCommandTStableV1WireStableV1::binprot_read( + &mut decoded_data[1..].as_ref(), + )?; + Ok(res) + } +} + impl Serialize for ConsensusBodyReferenceStableV1 { fn serialize(&self, serializer: S) -> Result where @@ -1468,6 +1548,10 @@ impl StagedLedgerDiffBodyStableV1 { } } + pub fn transactions(&self) -> impl Iterator { + self.commands_iter().map(|command| &command.data) + } + // FIXME(tizoc): this is not correct, the coinbases are in the commands // what this is returning is the coinbase fee transfers, which is not the same. pub fn coinbases_iter(&self) -> impl Iterator { @@ -1538,3 +1622,78 @@ impl StagedLedgerDiffBodyStableV1 { self.completed_works_iter().map(|v| v.fee.as_u64()).sum() } } + +// PicklesProofProofsVerifiedMaxStableV2 PicklesProofProofsVerified2ReprStableV2 + +impl From for PicklesProofProofsVerified2ReprStableV2 { + fn from(value: PicklesProofProofsVerifiedMaxStableV2) -> Self { + Self { + statement: value.statement, + prev_evals: value.prev_evals, + proof: value.proof, + } + } +} + +impl From for PicklesProofProofsVerifiedMaxStableV2 { + fn from(value: PicklesProofProofsVerified2ReprStableV2) -> Self { + Self { + statement: value.statement, + prev_evals: value.prev_evals, + proof: value.proof, + } + } +} + +impl std::fmt::Display for SgnStableV1 { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + SgnStableV1::Pos => write!(f, "Positive"), + SgnStableV1::Neg => write!(f, "Negative"), + } + } +} + +impl std::str::FromStr for SgnStableV1 { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + "Positive" => Ok(SgnStableV1::Pos), + "Negative" => Ok(SgnStableV1::Neg), + _ => Err("Invalid Sgn string, expected Positive or Negative".to_string()), + } + } +} + +#[cfg(test)] +mod test { + use binprot::BinProtRead; + + use crate::v2::{ + MinaBaseVerificationKeyWireStableV1, MinaBaseZkappCommandTStableV1WireStableV1, + }; + + #[test] + fn test_zkapp_with_sig_auth_hash() { + let expexcted = "AbliNXLg4Keq0ZJyxK/QNAx8SxrJeffYytk5lbcTF9s9Af0A4fUFAP2+oQMA48vntxcABLty3SXWjvuadrLtBjcsxT1oJ3C2hwS/LDh364LKUxrLe3uF/9lr8VlW/J+ctbiI+m9I61sb9BC/AAG5YjVy4OCnqtGScsSv0DQMfEsayXn32MrZOZW3ExfbPQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAAEBAQEBAQH9AJQ1dwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAAAAAePL57cXAAS7ct0l1o77mnay7QY3LMU9aCdwtocEvyw4d+uCylMay3t7hf/Za/FZVvyfnLW4iPpvSOtbG/QQvwAAAcwXZjv4NJwWwlJhFZPh2AK+o0dKOpIy1a6CXlskW7gmAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEAAQEBAQEBAf0AlDV3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAQEBAQAAAAICAAAAACIBFlRlc3QgWktBcHAgdG8gUmVjZWl2ZXIAAAAAAAAAAAAA".to_string(); + let bytes = include_bytes!("../../../tests/files/zkapps/with_sig_auth.bin"); + let zkapp = + MinaBaseZkappCommandTStableV1WireStableV1::binprot_read(&mut bytes.as_slice()).unwrap(); + + let zkapp_id = zkapp.to_base64().unwrap(); + assert_eq!(expexcted, zkapp_id); + } + + #[test] + fn test_verification_key_base64_decode() { + use base64::{engine::general_purpose::STANDARD, Engine as _}; + // let verification_key_encoded = "AACcenc1yLdGBm4xtUN1dpModROI0zovuy5rz2a94vfdBgG1C75BqviU4vw6JUYqODF8n9ivtfeU5s9PcpEGIP0htil2mfx8v2DB5RuNQ7VxJWkha0TSnJJsOl0FxhjldBbOY3tUZzZxHpPhHOKHz/ZAXRYFIsf2x+7boXC0iPurEX9VcnaJIq+YxxmnSfeYYxHkjxO9lrDBqjXzd5AHMnYyjTPC69B+5In7AOGS6R+A/g3/aR/MKDa4eDVrnsF9Oy/Ay8ahic2sSAZvtn08MdRyk/jm2cLlJbeAAad6Xyz/H9l7JrkbVwDMMPxvHVHs27tNoJCzIlrRzB7pg3ju9aQOu4h3thDr+WSgFQWKvcRPeL7f3TFjIr8WZ2457RgMcTwXwORKbqJCcyKVNOE+FlNwVkOKER+WIpC0OlgGuayPFwQQkbb91jaRlJvahfwkbF2+AJmDnavmNpop9T+/Xak1adXIrsRPeOjC+qIKxIbGimoMOoYzYlevKA80LnJ7HC0IxR+yNLvoSYxDDPNRD+OCCxk5lM2h8IDUiCNWH4FZNJ+doiigKjyZlu/xZ7jHcX7qibu/32KFTX85DPSkQM8dAEkH+vlkHmyXGLF4+xOVKeM0ihV5OEQrOABcgfTkbRsyxNInUBh0WiQyALE2ctjvkRCiE2P24bjFA8SgFmTM7gAKR89XcqLS/NP7lwCEej/L8q8R7sKGMCXmgFYluWH4JBSPDgvMxScfjFS33oBNb7po8cLnAORzohXoYTSgztklD0mKn6EegLbkLtwwr9ObsLz3m7fp/3wkNWFRkY5xzSZN1VybbQbmpyQNCpxd/kdDsvlszqlowkyC8HnKbhnvE0Mrz3ZIk4vSs/UGBSXAoESFCFCPcTq11TCOhE5rumMJErv5LusDHJgrBtQUMibLU9A1YbF7SPDAR2QZd0yx3waAC2F3xF+U682SOKF7oCZl2OICysRHqH+rZ604UfdGG0zWRuP2yg6kfGwcGQbO1ql40WrWTiFhbxxdKC7Gbz4y9Sb7q5EsPt6Z1AIn34/nXB/IWfC0gg/OgfPQTR7uxiTo2OOwjHni1f4KhT4rEmDAQn6ty6/ZRKHPWjUaAREbEw3tC36fI09hCYjjVTEmMAFTApk/tMUu0tC9Dt/vfDgXAlDJBwN5Y2Pt60qWY92skizVcWyWBxp5A8e4cVu3iToxOGUbSHzawovjubcH7qWjIZoghZJ16QB1c0ryiAfHB48OHhs2p/JZWz8Dp7kfcPkeg2Of2NbupJlNVMLIH4IGWaPAscBRkZ+F4oLqOhJ5as7fAzzU8PQdeZi0YgssGDJVmNEHP61I16KZNcxQqR0EUVwhyMmYmpVjvtfhHi/6I3TgYCmfnm6GL2sN144vMWg/gJ+p9a4GcEA0+gK3oCcKcwkq5rm+1Oxo9LWLp92Bdxq3iqfoIFmJ/ANGSbHF8StVmlVsP8zA+xuHylyiww/Lercce7cq0YA5PtYS3ge9IDYwXckBUXb5ikD3alrrv5mvMu6itB7ix2f8lbiF9Fkmc4Bk2ycIWXJDCuBN+2sTFqzUeoT6xY8XWaOcnDvqOgSm/CCSv38umiOE2jEpsKYxhRc6W70UJkrzd3hr2DiSF1I2B+krpUVK1GeOdCLC5sl7YPzk+pF8183uI9wse6UTlqiweZzB/ZVuZMnOUAmFHeq6Jb5mgW47a+FRWNXsjsA0KDFpNOoh5HYocETXS+LnAkAAADWhmIAAAADA=="; + let verification_key_encoded = "AACcenc1yLdGBm4xtUN1dpModROI0zovuy5rz2a94vfdBgG1C75BqviU4vw6JUYqODF8n9ivtfeU5s9PcpEGIP0htil2mfx8v2DB5RuNQ7VxJWkha0TSnJJsOl0FxhjldBbOY3tUZzZxHpPhHOKHz/ZAXRYFIsf2x+7boXC0iPurEX9VcnaJIq+YxxmnSfeYYxHkjxO9lrDBqjXzd5AHMnYyjTPC69B+5In7AOGS6R+A/g3/aR/MKDa4eDVrnsF9Oy/Ay8ahic2sSAZvtn08MdRyk/jm2cLlJbeAAad6Xyz/H9l7JrkbVwDMMPxvHVHs27tNoJCzIlrRzB7pg3ju9aQOu4h3thDr+WSgFQWKvcRPeL7f3TFjIr8WZ2457RgMcTwXwORKbqJCcyKVNOE+FlNwVkOKER+WIpC0OlgGuayPFwQQkbb91jaRlJvahfwkbF2+AJmDnavmNpop9T+/Xak1adXIrsRPeOjC+qIKxIbGimoMOoYzYlevKA80LnJ7HC0IxR+yNLvoSYxDDPNRD+OCCxk5lM2h8IDUiCNWH4FZNJ+doiigKjyZlu/xZ7jHcX7qibu/32KFTX85DPSkQM8dAEkH+vlkHmyXGLF4+xOVKeM0ihV5OEQrOABcgfTkbRsyxNInUBh0WiQyALE2ctjvkRCiE2P24bjFA8SgFmTM7gAKR89XcqLS/NP7lwCEej/L8q8R7sKGMCXmgFYluWH4JBSPDgvMxScfjFS33oBNb7po8cLnAORzohXoYTSgztklD0mKn6EegLbkLtwwr9ObsLz3m7fp/3wkNWFRkY5xzSZN1VybbQbmpyQNCpxd/kdDsvlszqlowkyC8HnKbhnvE0Mrz3ZIk4vSs/UGBSXAoESFCFCPcTq11TCOhE5rumMJErv5LusDHJgrBtQUMibLU9A1YbF7SPDAR2QZd0yx3waAC2F3xF+U682SOKF7oCZl2OICysRHqH+rZ604UfdGG0zWRuP2yg6kfGwcGQbO1ql40WrWTiFhbxxdKC7Gbz4y9Sb7q5EsPt6Z1AIn34/nXB/IWfC0gg/OgfPQTR7uxiTo2OOwjHni1f4KhT4rEmDAQn6ty6/ZRKHPWjUaAREbEw3tC36fI09hCYjjVTEmMAFTApk/tMUu0tC9Dt/vfDgXAlDJBwN5Y2Pt60qWY92skizVcWyWBxp5A8e4cVu3iToxOGUbSHzawovjubcH7qWjIZoghZJ16QB1c0ryiAfHB48OHhs2p/JZWz8Dp7kfcPkeg2Of2NbupJlNVMLIH4IGWaPAscBRkZ+F4oLqOhJ5as7fAzzU8PQdeZi0YgssGDJVmNEHP61I16KZNcxQqR0EUVwhyMmYmpVjvtfhHi/6I3TgYCmfnm6GL2sN144vMWg/gJ+p9a4GcEA0+gK3oCcKcwkq5rm+1Oxo9LWLp92Bdxq3iqfoIFmJ/ANGSbHF8StVmlVsP8zA+xuHylyiww/Lercce7cq0YA5PtYS3ge9IDYwXckBUXb5ikD3alrrv5mvMu6itB7ix2f8lbiF9Fkmc4Bk2ycIWXJDCuBN+2sTFqzUeoT6xY8XWaOcnDvqOgSm/CCSv38umiOE2jEpsKYxhRc6W70UJkrzd3hr2DiSF1I2B+krpUVK1GeOdCLC5sl7YPzk+pF8183uI9wse6UTlqIiroKqsggzLBy/IjAfxS0BxFy5zywXqp+NogFkoTEJmR5MaqOkPfap+OsD1lGScY6+X4WW/HqCWrmA3ZTqDGngQMTGXLCtl6IS/cQpihS1NRbNqOtKTaCB9COQu0oz6RivBlywuaj3MKUdmbQ2gVDj+SGQItCNaXawyPSBjB9VT+68SoJVySQsYPCuEZCb0V/40n/a7RAbyrnNjP+2HwD7p27Pl1RSzqq35xiPdnycD1UeEPLpx/ON65mYCkn+KLQZmkqPio+vA2KmJngWTx+ol4rVFimGm76VT0xCFDsu2K0YX0yoLNH4u2XfmT9NR8gGfkVRCnnNjlbgHQmEwC75+GmEJ5DjD3d+s6IXTQ60MHvxbTHHlnfmPbgKn2SAI0uVoewKC9GyK6dSaboLw3C48jl0E2kyc+7umhCk3kEeWmt//GSjRNhoq+B+mynXiOtgFs/Am2v1TBjSb+6tcijsf5tFJmeGxlCjJnTdNWBkSHpMoo6OFkkpA6/FBAUHLSM7Yv8oYyd0GtwF5cCwQ6aRTbl9oG/mUn5Q92OnDMQcUjpgEho0Dcp2OqZyyxqQSPrbIIZZQrS2HkxBgjcfcSTuSHo7ONqlRjLUpO5yS95VLGXBLLHuCiIMGT+DW6DoJRtRIS+JieVWBoX0YsWgYInXrVlWUv6gDng5AyVFkUIFwZk7/3mVAgvXO83ArVKA4S747jT60w5bgV4Jy55slDM="; + + let decoded = STANDARD.decode(verification_key_encoded).unwrap(); + let verification_key = + MinaBaseVerificationKeyWireStableV1::binprot_read(&mut decoded.as_slice()); + assert!(verification_key.is_ok()); + } +} diff --git a/mina-p2p-messages/src/v2/manual/conv.rs b/mina-p2p-messages/src/v2/manual/conv.rs index 38c6bd8bdb..cda2256e51 100644 --- a/mina-p2p-messages/src/v2/manual/conv.rs +++ b/mina-p2p-messages/src/v2/manual/conv.rs @@ -4,6 +4,16 @@ use crate::v2::{ MinaTransactionLogicTransactionAppliedVaryingStableV2, MinaTransactionTransactionStableV2, }; +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("Binprot error: {0}")] + BinProt(#[from] binprot::Error), + #[error("Base64 error: {0}")] + Base64(#[from] base64::DecodeError), + #[error("IO error: {0}")] + Io(#[from] std::io::Error), +} + /// Extract transaction data and status required by proof generation impl From for ( diff --git a/mina-p2p-messages/src/v2/mod.rs b/mina-p2p-messages/src/v2/mod.rs index 2b4b29df47..7f8fda680f 100644 --- a/mina-p2p-messages/src/v2/mod.rs +++ b/mina-p2p-messages/src/v2/mod.rs @@ -2,6 +2,9 @@ mod generated; mod hashing; mod manual; +mod dummy; +pub use dummy::*; + pub use generated::*; pub use hashing::*; pub use manual::*; diff --git a/node/Cargo.toml b/node/Cargo.toml index 577cdccb7f..7cf1e0795a 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "node" -version = "0.9.0" +version = "0.10.0" edition = "2021" license = "Apache-2.0" diff --git a/node/account/Cargo.toml b/node/account/Cargo.toml index d29572551d..fb1541ef25 100644 --- a/node/account/Cargo.toml +++ b/node/account/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openmina-node-account" -version = "0.9.0" +version = "0.10.0" edition = "2021" license = "Apache-2.0" diff --git a/node/common/Cargo.toml b/node/common/Cargo.toml index 02d9ea2864..9d347d5e47 100644 --- a/node/common/Cargo.toml +++ b/node/common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openmina-node-common" -version = "0.9.0" +version = "0.10.0" edition = "2021" license = "Apache-2.0" diff --git a/node/common/src/service/rpc/ledger.rs b/node/common/src/service/rpc/ledger.rs new file mode 100644 index 0000000000..dd6d3b273b --- /dev/null +++ b/node/common/src/service/rpc/ledger.rs @@ -0,0 +1,75 @@ +#[cfg(target_family = "wasm")] +use gloo_utils::format::JsValueSerdeExt; +use node::rpc::*; +#[cfg(target_family = "wasm")] +use wasm_bindgen::prelude::*; + +use super::RpcSender; + +#[derive(Clone)] +#[cfg_attr(target_family = "wasm", wasm_bindgen)] +pub struct Ledger { + #[allow(unused)] + sender: RpcSender, +} + +#[derive(Clone)] +#[cfg_attr(target_family = "wasm", wasm_bindgen)] +pub struct LedgerSelected { + #[allow(unused)] + sender: RpcSender, +} + +#[derive(Clone)] +#[cfg_attr(target_family = "wasm", wasm_bindgen)] +pub struct LedgerAccounts { + #[allow(unused)] + sender: RpcSender, +} + +impl Ledger { + pub fn new(sender: RpcSender) -> Self { + Self { sender } + } +} + +#[cfg_attr(target_family = "wasm", wasm_bindgen)] +impl Ledger { + pub fn latest(&self) -> LedgerSelected { + LedgerSelected { + sender: self.sender.clone(), + } + } +} + +#[cfg_attr(target_family = "wasm", wasm_bindgen)] +impl LedgerSelected { + pub fn accounts(&self) -> LedgerAccounts { + LedgerAccounts { + sender: self.sender.clone(), + } + } +} + +impl LedgerAccounts { + async fn _all(&self) -> Option { + self.sender + .oneshot_request(RpcRequest::LedgerAccountsGet(AccountQuery::All)) + .await + } +} + +#[cfg(not(target_family = "wasm"))] +impl LedgerAccounts { + pub async fn all(&self) -> Option { + self._all().await + } +} + +#[cfg(target_family = "wasm")] +#[cfg_attr(target_family = "wasm", wasm_bindgen)] +impl LedgerAccounts { + pub async fn all(&self) -> JsValue { + JsValue::from_serde(&self._all().await).unwrap_or_default() + } +} diff --git a/node/common/src/service/rpc/mod.rs b/node/common/src/service/rpc/mod.rs index 5d59e9b6d8..3ce53f9b30 100644 --- a/node/common/src/service/rpc/mod.rs +++ b/node/common/src/service/rpc/mod.rs @@ -1,15 +1,19 @@ mod sender; pub use sender::RpcSender; +pub mod ledger; pub mod state; pub mod stats; +pub mod transaction_pool; +pub mod transition_frontier; use node::rpc::{ - RpcBlockProducerStatsGetResponse, RpcDiscoveryBoostrapStatsResponse, - RpcDiscoveryRoutingTableResponse, RpcHealthCheckResponse, RpcLedgerAccountsResponse, - RpcMessageProgressResponse, RpcPeersGetResponse, RpcReadinessCheckResponse, RpcRequest, - RpcStateGetError, RpcStatusGetResponse, RpcTransactionInjectResponse, - RpcTransactionPoolResponse, RpcTransitionFrontierUserCommandsResponse, + RpcBestChainResponse, RpcBlockProducerStatsGetResponse, RpcConsensusConstantsGetResponse, + RpcDiscoveryBoostrapStatsResponse, RpcDiscoveryRoutingTableResponse, RpcHealthCheckResponse, + RpcLedgerAccountsResponse, RpcLedgerSlimAccountsResponse, RpcMessageProgressResponse, + RpcPeersGetResponse, RpcReadinessCheckResponse, RpcRequest, RpcStateGetError, + RpcStatusGetResponse, RpcTransactionInjectResponse, RpcTransactionPoolResponse, + RpcTransactionStatusGetResponse, RpcTransitionFrontierUserCommandsResponse, }; use serde::{Deserialize, Serialize}; @@ -286,12 +290,19 @@ impl node::rpc::RpcService for NodeService { RpcDiscoveryBoostrapStatsResponse ); rpc_service_impl!(respond_transaction_pool, RpcTransactionPoolResponse); + rpc_service_impl!(respond_ledger_slim_accounts, RpcLedgerSlimAccountsResponse); rpc_service_impl!(respond_ledger_accounts, RpcLedgerAccountsResponse); rpc_service_impl!(respond_transaction_inject, RpcTransactionInjectResponse); rpc_service_impl!( respond_transition_frontier_commands, RpcTransitionFrontierUserCommandsResponse ); + rpc_service_impl!(respond_best_chain, RpcBestChainResponse); + rpc_service_impl!( + respond_consensus_constants, + RpcConsensusConstantsGetResponse + ); + rpc_service_impl!(respond_transaction_status, RpcTransactionStatusGetResponse); } #[cfg(test)] diff --git a/node/common/src/service/rpc/sender.rs b/node/common/src/service/rpc/sender.rs index 978f398a64..d0357338d6 100644 --- a/node/common/src/service/rpc/sender.rs +++ b/node/common/src/service/rpc/sender.rs @@ -8,8 +8,11 @@ use node::core::channels::{mpsc, oneshot}; use node::p2p::connection::outgoing::P2pConnectionOutgoingInitOpts; use node::rpc::*; +use super::ledger::Ledger; use super::state::State; use super::stats::Stats; +use super::transaction_pool::TransactionPool; +use super::transition_frontier::TransitionFrontier; use super::NodeRpcRequest; #[derive(Clone)] @@ -76,6 +79,18 @@ impl RpcSender { pub fn stats(&self) -> Stats { Stats::new(self.clone()) } + + pub fn transaction_pool(&self) -> TransactionPool { + TransactionPool::new(self.clone()) + } + + pub fn transition_frontier(&self) -> TransitionFrontier { + TransitionFrontier::new(self.clone()) + } + + pub fn ledger(&self) -> Ledger { + Ledger::new(self.clone()) + } } #[cfg(target_family = "wasm")] diff --git a/node/common/src/service/rpc/transaction_pool.rs b/node/common/src/service/rpc/transaction_pool.rs new file mode 100644 index 0000000000..b1bbfa41ce --- /dev/null +++ b/node/common/src/service/rpc/transaction_pool.rs @@ -0,0 +1,105 @@ +#[cfg(target_family = "wasm")] +use gloo_utils::format::JsValueSerdeExt; +use mina_p2p_messages::v2; +use node::rpc::*; +#[cfg(target_family = "wasm")] +use wasm_bindgen::prelude::*; + +use super::RpcSender; + +#[derive(Clone)] +#[cfg_attr(target_family = "wasm", wasm_bindgen)] +pub struct TransactionPool { + #[allow(unused)] + sender: RpcSender, +} + +#[derive(Clone)] +#[cfg_attr(target_family = "wasm", wasm_bindgen)] +pub struct TransactionPoolInject { + #[allow(unused)] + sender: RpcSender, +} + +impl TransactionPool { + pub fn new(sender: RpcSender) -> Self { + Self { sender } + } + + async fn _get(&self) -> Option { + self.sender + .oneshot_request(RpcRequest::TransactionPoolGet) + .await + } +} + +#[cfg_attr(target_family = "wasm", wasm_bindgen)] +impl TransactionPool { + pub fn inject(&self) -> TransactionPoolInject { + TransactionPoolInject { + sender: self.sender.clone(), + } + } +} + +#[cfg(not(target_family = "wasm"))] +impl TransactionPool { + pub async fn get(&self) -> Option { + self._get().await + } +} + +#[cfg(target_family = "wasm")] +#[cfg_attr(target_family = "wasm", wasm_bindgen)] +impl TransactionPool { + pub async fn get(&self) -> JsValue { + JsValue::from_serde(&self._get().await).unwrap_or_default() + } +} + +impl TransactionPoolInject { + async fn _payment( + &self, + payments: Vec, + ) -> Result, String> { + let res = self + .sender + .oneshot_request(RpcRequest::TransactionInject( + payments + .into_iter() + .map(v2::MinaBaseUserCommandStableV2::try_from) + .collect::>() + .map_err(|err| err.to_string())?, + )) + .await; + Ok(res) + } +} + +#[cfg(not(target_family = "wasm"))] +impl TransactionPoolInject { + pub async fn payment( + &self, + payments: Vec, + ) -> Result, String> { + self._payment(payments).await + } +} + +#[cfg(target_family = "wasm")] +#[cfg_attr(target_family = "wasm", wasm_bindgen)] +impl TransactionPoolInject { + pub async fn payment(&self, payments: JsValue) -> Result { + let payments: Vec = if payments.is_array() { + payments.into_serde().map_err(|err| err.to_string())? + } else { + let payment = payments.into_serde().map_err(|err| err.to_string())?; + vec![payment] + }; + + self._payment(payments) + .await + .map(|res| JsValue::from_serde(&res).unwrap_or_default()) + .map_err(Into::into) + } +} diff --git a/node/common/src/service/rpc/transition_frontier.rs b/node/common/src/service/rpc/transition_frontier.rs new file mode 100644 index 0000000000..b92f1cfc52 --- /dev/null +++ b/node/common/src/service/rpc/transition_frontier.rs @@ -0,0 +1,59 @@ +#[cfg(target_family = "wasm")] +use gloo_utils::format::JsValueSerdeExt; +use node::rpc::*; +#[cfg(target_family = "wasm")] +use wasm_bindgen::prelude::*; + +use super::RpcSender; + +#[derive(Clone)] +#[cfg_attr(target_family = "wasm", wasm_bindgen)] +pub struct TransitionFrontier { + #[allow(unused)] + sender: RpcSender, +} + +#[derive(Clone)] +#[cfg_attr(target_family = "wasm", wasm_bindgen)] +pub struct TransitionFrontierBestChain { + #[allow(unused)] + sender: RpcSender, +} + +impl TransitionFrontier { + pub fn new(sender: RpcSender) -> Self { + Self { sender } + } +} + +#[cfg_attr(target_family = "wasm", wasm_bindgen)] +impl TransitionFrontier { + pub fn best_chain(&self) -> TransitionFrontierBestChain { + TransitionFrontierBestChain { + sender: self.sender.clone(), + } + } +} + +impl TransitionFrontierBestChain { + async fn _user_commands(&self) -> Option { + self.sender + .oneshot_request(RpcRequest::TransitionFrontierUserCommandsGet) + .await + } +} + +#[cfg(not(target_family = "wasm"))] +impl TransitionFrontierBestChain { + pub async fn user_commands(&self) -> Option { + self._user_commands().await + } +} + +#[cfg(target_family = "wasm")] +#[cfg_attr(target_family = "wasm", wasm_bindgen)] +impl TransitionFrontierBestChain { + pub async fn user_commands(&self) -> JsValue { + JsValue::from_serde(&self._user_commands().await).unwrap_or_default() + } +} diff --git a/node/invariants/Cargo.toml b/node/invariants/Cargo.toml index e599a3be3e..3636c94ea0 100644 --- a/node/invariants/Cargo.toml +++ b/node/invariants/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openmina-node-invariants" -version = "0.9.0" +version = "0.10.0" edition = "2021" license = "Apache-2.0" diff --git a/node/native/Cargo.toml b/node/native/Cargo.toml index 1e1865ae87..30d3451d49 100644 --- a/node/native/Cargo.toml +++ b/node/native/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openmina-node-native" -version = "0.9.0" +version = "0.10.0" edition = "2021" license = "Apache-2.0" @@ -15,8 +15,8 @@ tokio = { version = "1.26.0", features = ["process", "macros"] } reqwest = { version = "0.11.24", features = ["blocking", "json"] } warp = "0.3" libp2p-identity = { version = "=0.2.7", features = ["peerid"] } -juniper = { version = "0.15.11" } -juniper_warp = { version = "0.7.0" } +juniper = { workspace = true } +juniper_warp = { version = "0.8.0" } redux = { workspace = true, features=["serializable_callbacks"] } ledger = { workspace = true } mina-p2p-messages = { workspace = true } @@ -30,6 +30,8 @@ nix = { version = "0.26.2", features = ["signal"] } vrf = { workspace = true } jsonpath-rust = "0.5.0" sha3 = "0.10.8" +strum = "0.26.2" +strum_macros = "0.26.4" openmina-core = { path = "../../core" } openmina-node-common = { path = "../common" } diff --git a/node/native/src/graphql.rs b/node/native/src/graphql.rs deleted file mode 100644 index 32cd428aca..0000000000 --- a/node/native/src/graphql.rs +++ /dev/null @@ -1,153 +0,0 @@ -use juniper::{EmptyMutation, EmptySubscription, GraphQLEnum, RootNode}; -use node::{ - rpc::{RpcRequest, RpcSyncStatsGetResponse, SyncStatsQuery}, - stats::sync::SyncKind, -}; -use openmina_node_common::rpc::RpcSender; -use warp::{Filter, Rejection, Reply}; - -struct Context(RpcSender); - -impl juniper::Context for Context {} - -#[derive(Clone, Copy, Debug, GraphQLEnum)] -#[allow(clippy::upper_case_acronyms)] -enum SyncStatus { - CONNECTING, - LISTENING, - OFFLINE, - BOOTSTRAP, - SYNCED, - CATCHUP, -} - -#[derive(Clone, Debug)] -struct ProtocolState { - consensus_state: ConsensusState, - blockchain_state: BlockchainState, -} - -#[juniper::graphql_object(context = Context)] -impl ProtocolState { - fn consensus_state(&self) -> &ConsensusState { - &self.consensus_state - } - - fn blockchain_state(&self) -> &BlockchainState { - &self.blockchain_state - } -} - -#[derive(Clone, Debug)] -struct ConsensusState { - block_height: i32, -} - -#[juniper::graphql_object(context = Context)] -impl ConsensusState { - fn block_height(&self) -> i32 { - self.block_height - } -} - -#[derive(Clone, Debug)] -struct BlockchainState { - snarked_ledger_hash: String, -} - -#[juniper::graphql_object(context = Context)] -impl BlockchainState { - fn snarked_ledger_hash(&self) -> &str { - &self.snarked_ledger_hash - } -} - -#[derive(Clone, Debug)] -struct BestChain { - state_hash: String, - protocol_state: ProtocolState, -} - -#[juniper::graphql_object(context = Context)] -impl BestChain { - fn state_hash(&self) -> &str { - &self.state_hash - } - - fn protocol_state(&self) -> &ProtocolState { - &self.protocol_state - } -} - -#[derive(Clone, Copy, Debug)] -struct Query; - -#[juniper::graphql_object(context = Context)] -impl Query { - async fn sync_status(context: &Context) -> SyncStatus { - let state: RpcSyncStatsGetResponse = context - .0 - .oneshot_request(RpcRequest::SyncStatsGet(SyncStatsQuery { limit: Some(1) })) - .await - .unwrap(); - - if let Some(state) = state.as_ref().and_then(|s| s.first()) { - if state.synced.is_some() { - SyncStatus::SYNCED - } else { - match &state.kind { - SyncKind::Bootstrap => SyncStatus::BOOTSTRAP, - SyncKind::Catchup => SyncStatus::CATCHUP, - } - } - } else { - SyncStatus::LISTENING - } - } - - async fn best_chain(max_length: i32, context: &Context) -> Vec { - let state: RpcSyncStatsGetResponse = context - .0 - .oneshot_request(RpcRequest::SyncStatsGet(SyncStatsQuery { - limit: Some(max_length as _), - })) - .await - .unwrap(); - state - .unwrap_or_default() - .into_iter() - .filter_map(|x| { - let head = x.blocks.first()?; - let snarked_ledger_hash = x.ledgers.root?.snarked.hash?; - Some(BestChain { - state_hash: head.hash.to_string(), - protocol_state: ProtocolState { - consensus_state: ConsensusState { - block_height: head.height as _, - }, - blockchain_state: BlockchainState { - snarked_ledger_hash: snarked_ledger_hash.to_string(), - }, - }, - }) - }) - .collect() - } -} - -pub fn routes( - rpc_sernder: RpcSender, -) -> impl Filter + Clone { - let state = warp::any().map(move || Context(rpc_sernder.clone())); - let schema = RootNode::new( - Query, - EmptyMutation::::new(), - EmptySubscription::::new(), - ); - let graphql_filter = juniper_warp::make_graphql_filter(schema, state.boxed()); - - warp::get() - .and(warp::path("graphiql")) - .and(juniper_warp::graphiql_filter("/graphql", None)) - .or(warp::path("graphql").and(graphql_filter)) -} diff --git a/node/native/src/graphql/account.rs b/node/native/src/graphql/account.rs new file mode 100644 index 0000000000..1d661b869b --- /dev/null +++ b/node/native/src/graphql/account.rs @@ -0,0 +1,243 @@ +use juniper::{GraphQLInputObject, GraphQLObject}; +use ledger::FpExt; +use mina_p2p_messages::{ + string::{TokenSymbol, ZkAppUri}, + v2::{ + MinaBaseAccountUpdateUpdateTimingInfoStableV1, MinaBaseVerificationKeyWireStableV1, + ReceiptChainHash, TokenIdKeyHash, + }, +}; + +use super::ConversionError; + +#[derive(GraphQLObject, Debug)] +#[graphql(description = "A Mina account")] +pub struct GraphQLAccount { + pub public_key: String, + pub token_id: String, + pub token: String, + pub token_symbol: String, + pub balance: GraphQLBalance, + pub nonce: String, + pub receipt_chain_hash: String, + // TODO(adonagy): this should be GraphQLAccount recursively + pub delegate_account: Option, + pub voting_for: String, + pub timing: GraphQLTiming, + pub permissions: GraphQLPermissions, + // can we flatten? + // pub zkapp: Option, + pub zkapp_state: Option>, + pub verification_key: Option, + pub action_state: Option>, + pub proved_state: Option, + pub zkapp_uri: Option, +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLDelegateAccount { + pub public_key: String, +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLTiming { + // pub is_timed: bool, + pub initial_minimum_balance: Option, + pub cliff_time: Option, + pub cliff_amount: Option, + pub vesting_period: Option, + pub vesting_increment: Option, +} + +#[derive(GraphQLInputObject, Debug)] +pub struct InputGraphQLTiming { + // pub is_timed: bool, + pub initial_minimum_balance: String, + pub cliff_time: i32, + pub cliff_amount: String, + pub vesting_period: i32, + pub vesting_increment: String, +} + +impl From for GraphQLTiming { + fn from(value: MinaBaseAccountUpdateUpdateTimingInfoStableV1) -> Self { + Self { + initial_minimum_balance: Some(value.initial_minimum_balance.0.as_u64().to_string()), + cliff_time: Some(value.cliff_time.as_u32() as i32), + cliff_amount: Some(value.cliff_amount.as_u64().to_string()), + vesting_period: Some(value.vesting_period.as_u32() as i32), + vesting_increment: Some(value.vesting_increment.0.as_u64().to_string()), + } + } +} +#[derive(GraphQLObject, Debug)] +pub struct GraphQLPermissions { + pub edit_state: String, + pub access: String, + pub send: String, + pub receive: String, + pub set_delegate: String, + pub set_permissions: String, + pub set_verification_key: GraphQLSetVerificationKey, + pub set_zkapp_uri: String, + pub edit_action_state: String, + pub set_token_symbol: String, + pub increment_nonce: String, + pub set_voting_for: String, + pub set_timing: String, +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLSetVerificationKey { + pub auth: String, + pub txn_version: String, +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLBalance { + pub total: String, +} + +// #[derive(GraphQLObject, Debug)] +// pub struct GraphQLZkAppAccount { +// pub app_state: Vec, +// pub verification_key: Option, +// pub zkapp_version: i32, +// pub action_state: Vec, +// pub last_action_slot: i32, +// pub proved_state: bool, +// pub zkapp_uri: String, +// } + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLVerificationKey { + // pub max_proofs_verified: String, + // pub actual_wrap_domain_size: String, + // pub wrap_index: String, + pub verification_key: String, + pub hash: String, +} + +impl From> for GraphQLSetVerificationKey { + fn from(value: ledger::SetVerificationKey) -> Self { + Self { + auth: value.auth.to_string(), + txn_version: value.txn_version.as_u32().to_string(), + } + } +} + +impl From> for GraphQLPermissions { + fn from(value: ledger::Permissions) -> Self { + Self { + edit_state: value.edit_state.to_string(), + access: value.access.to_string(), + send: value.send.to_string(), + receive: value.receive.to_string(), + set_delegate: value.set_delegate.to_string(), + set_permissions: value.set_permissions.to_string(), + set_verification_key: GraphQLSetVerificationKey::from(value.set_verification_key), + set_zkapp_uri: value.set_zkapp_uri.to_string(), + edit_action_state: value.edit_action_state.to_string(), + set_token_symbol: value.set_token_symbol.to_string(), + increment_nonce: value.increment_nonce.to_string(), + set_voting_for: value.set_voting_for.to_string(), + set_timing: value.set_timing.to_string(), + } + } +} + +impl From for GraphQLTiming { + fn from(value: ledger::Timing) -> Self { + match value { + ledger::Timing::Untimed => Self { + initial_minimum_balance: None, + vesting_period: None, + cliff_time: None, + cliff_amount: None, + vesting_increment: None, + }, + ledger::Timing::Timed { + initial_minimum_balance, + cliff_time, + cliff_amount, + vesting_period, + vesting_increment, + } => Self { + initial_minimum_balance: Some(initial_minimum_balance.as_u64().to_string()), + cliff_time: Some(cliff_time.as_u32() as i32), + cliff_amount: Some(cliff_amount.as_u64().to_string()), + vesting_period: Some(vesting_period.as_u32() as i32), + vesting_increment: Some(vesting_increment.as_u64().to_string()), + }, + } + } +} + +// TODO(adonagy) +impl From for GraphQLBalance { + fn from(value: ledger::scan_state::currency::Balance) -> Self { + Self { + total: value.as_u64().to_string(), + } + } +} + +impl TryFrom for GraphQLAccount { + type Error = ConversionError; + + fn try_from(value: ledger::Account) -> Result { + // Process the verification_key with proper error handling + let verification_key = value + .zkapp + .clone() + .and_then(|zkapp| { + zkapp.verification_key.map(|vk| { + let ser = MinaBaseVerificationKeyWireStableV1::from(vk.vk()).to_base64()?; + + Ok(GraphQLVerificationKey { + verification_key: ser, + hash: vk.hash().to_decimal(), + }) as Result + }) + }) + .transpose()?; // Transpose Option> to Result> + + Ok(Self { + public_key: value.public_key.into_address(), + token_id: TokenIdKeyHash::from(value.token_id.clone()).to_string(), + token: TokenIdKeyHash::from(value.token_id).to_string(), + token_symbol: TokenSymbol::from(&value.token_symbol).to_string(), + balance: GraphQLBalance::from(value.balance), + nonce: value.nonce.as_u32().to_string(), + receipt_chain_hash: ReceiptChainHash::from(value.receipt_chain_hash).to_string(), + delegate_account: value.delegate.map(|d| GraphQLDelegateAccount { + public_key: d.into_address(), + }), + voting_for: value.voting_for.to_base58check_graphql(), + timing: GraphQLTiming::from(value.timing), + permissions: GraphQLPermissions::from(value.permissions), + // zkapp: value.zkapp.map(GraphQLZkAppAccount::from), + // TODO: keep as array? + zkapp_state: value.zkapp.clone().map(|zkapp| { + zkapp + .app_state + .into_iter() + .map(|v| v.to_decimal()) + .collect::>() + }), + verification_key, + action_state: value.zkapp.clone().map(|zkapp| { + zkapp + .action_state + .into_iter() + .map(|v| v.to_decimal()) + .collect::>() + }), + proved_state: value.zkapp.clone().map(|zkapp| zkapp.proved_state), + zkapp_uri: value + .zkapp + .map(|zkapp| ZkAppUri::from(&zkapp.zkapp_uri).to_string()), + }) + } +} diff --git a/node/native/src/graphql/block.rs b/node/native/src/graphql/block.rs new file mode 100644 index 0000000000..5a28a06b51 --- /dev/null +++ b/node/native/src/graphql/block.rs @@ -0,0 +1,260 @@ +use juniper::GraphQLObject; +use openmina_core::block::AppliedBlock; + +use crate::graphql::zkapp::{GraphQLFailureReason, GraphQLFeePayer, GraphQLZkappCommand}; + +use super::{zkapp::GraphQLZkapp, ConversionError}; + +#[derive(GraphQLObject, Debug)] +#[graphql(description = "A Mina block")] +pub struct GraphQLBestChainBlock { + pub protocol_state: GraphQLProtocolState, + pub state_hash: String, + pub transactions: GraphQLTransactions, +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLTransactions { + pub zkapp_commands: Vec, +} + +impl TryFrom for GraphQLBestChainBlock { + type Error = ConversionError; + fn try_from(value: AppliedBlock) -> Result { + let block = value.block; + let blockchain_state = GraphQLBlockchainState { + snarked_ledger_hash: block.snarked_ledger_hash().to_string(), + staged_ledger_hash: block + .staged_ledger_hashes() + .non_snark + .ledger_hash + .to_string(), + date: block + .header() + .protocol_state + .body + .blockchain_state + .timestamp + .to_string(), + utc_date: block + .header() + .protocol_state + .body + .blockchain_state + .timestamp + .to_string(), + staged_ledger_proof_emitted: value.just_emitted_a_proof, + }; + + let protocol_state = GraphQLProtocolState { + previous_state_hash: block.pred_hash().to_string(), + blockchain_state, + consensus_state: block + .header() + .protocol_state + .body + .consensus_state + .clone() + .into(), + }; + + Ok(Self { + protocol_state, + state_hash: block.hash.to_string(), + transactions: block.body().diff().clone().try_into()?, + }) + } +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLProtocolState { + pub previous_state_hash: String, + pub blockchain_state: GraphQLBlockchainState, + pub consensus_state: GraphQLConsensusState, +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLBlockchainState { + pub snarked_ledger_hash: String, + pub staged_ledger_hash: String, + pub date: String, + pub utc_date: String, + pub staged_ledger_proof_emitted: bool, +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLConsensusState { + pub block_height: String, + pub slot_since_genesis: String, + pub slot: String, + pub next_epoch_data: GraphQLEpochData, + pub staking_epoch_data: GraphQLEpochData, + pub epoch_count: String, + pub min_window_density: String, + pub total_currency: String, + pub epoch: String, +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLEpochData { + pub ledger: GraphQLLedger, + pub seed: String, + pub start_checkpoint: String, + pub lock_checkpoint: String, + pub epoch_length: String, +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLLedger { + pub hash: String, + pub total_currency: String, +} + +impl TryFrom for GraphQLTransactions { + type Error = ConversionError; + fn try_from( + value: mina_p2p_messages::v2::StagedLedgerDiffDiffDiffStableV2, + ) -> Result { + use mina_p2p_messages::v2::{ + MinaBaseTransactionStatusStableV2, MinaBaseUserCommandStableV2, + }; + + let also_zkapp_commands = value + .1 + .map_or_else(Vec::new, |v| v.commands.into_iter().collect::>()); + + let zkapp_commands = value + .0 + .commands + .into_iter() + .chain(also_zkapp_commands) + .rev() + .map(|cmd| { + // std::fs::create_dir_all("zkapps").unwrap(); + // let zkapp_path = format!("zkapps/{}", zkapp.hash().unwrap()); + // let path = PathBuf::from(zkapp_path.clone()); + // if !path.exists() { + // let mut buff = Vec::new(); + // zkapp.binprot_write(&mut buff).unwrap(); + // std::fs::write(zkapp_path, buff).unwrap(); + // } + if let MinaBaseUserCommandStableV2::ZkappCommand(zkapp) = cmd.data { + let failure_reason = + if let MinaBaseTransactionStatusStableV2::Failed(failure_collection) = + cmd.status + { + let res = failure_collection + .0 + .into_iter() + .enumerate() + .skip(1) + .map(|(index, failure_list)| { + let fl = + failure_list.into_iter().map(|v| v.to_string()).collect(); + GraphQLFailureReason { + index: index.to_string(), + failures: fl, + } + }) + .rev() + .collect(); + Some(res) + } else { + None + }; + let account_updates = zkapp + .account_updates + .clone() + .into_iter() + .map(|v| v.elt.account_update.try_into()) + .collect::, _>>()?; + Ok(Some(GraphQLZkapp { + hash: zkapp.hash()?.to_string(), + failure_reason, + id: zkapp.to_base64()?, + zkapp_command: GraphQLZkappCommand { + memo: zkapp.memo.to_base58check(), + account_updates, + fee_payer: GraphQLFeePayer::from(zkapp.fee_payer), + }, + })) + } else { + Ok(None) + } + }) + .collect::, Self::Error>>()? + .into_iter() + .flatten() + .collect::>(); + Ok(Self { zkapp_commands }) + } +} + +impl From for GraphQLLedger { + fn from(value: mina_p2p_messages::v2::MinaBaseEpochLedgerValueStableV1) -> Self { + Self { + hash: value.hash.to_string(), + total_currency: value.total_currency.as_u64().to_string(), + } + } +} + +impl From + for GraphQLEpochData +{ + fn from( + value: mina_p2p_messages::v2::ConsensusProofOfStakeDataEpochDataNextValueVersionedValueStableV1, + ) -> Self { + Self { + ledger: value.ledger.into(), + seed: value.seed.to_string(), + start_checkpoint: value.start_checkpoint.to_string(), + lock_checkpoint: value.lock_checkpoint.to_string(), + epoch_length: value.epoch_length.as_u32().to_string(), + } + } +} + +impl + From< + mina_p2p_messages::v2::ConsensusProofOfStakeDataEpochDataStakingValueVersionedValueStableV1, + > for GraphQLEpochData +{ + fn from( + value: mina_p2p_messages::v2::ConsensusProofOfStakeDataEpochDataStakingValueVersionedValueStableV1, + ) -> Self { + Self { + ledger: value.ledger.into(), + seed: value.seed.to_string(), + start_checkpoint: value.start_checkpoint.to_string(), + lock_checkpoint: value.lock_checkpoint.to_string(), + epoch_length: value.epoch_length.as_u32().to_string(), + } + } +} + +impl From + for GraphQLConsensusState +{ + fn from( + value: mina_p2p_messages::v2::ConsensusProofOfStakeDataConsensusStateValueStableV2, + ) -> Self { + let slot = value.curr_global_slot_since_hard_fork.slot_number.as_u32() + % value + .curr_global_slot_since_hard_fork + .slots_per_epoch + .as_u32(); + + Self { + block_height: value.blockchain_length.as_u32().to_string(), + slot_since_genesis: value.global_slot_since_genesis.as_u32().to_string(), + slot: slot.to_string(), + next_epoch_data: value.next_epoch_data.into(), + staking_epoch_data: value.staking_epoch_data.into(), + epoch_count: value.epoch_count.as_u32().to_string(), + min_window_density: value.min_window_density.as_u32().to_string(), + total_currency: value.total_currency.as_u64().to_string(), + epoch: value.epoch_count.as_u32().to_string(), + } + } +} diff --git a/node/native/src/graphql/constants.rs b/node/native/src/graphql/constants.rs new file mode 100644 index 0000000000..1551736b21 --- /dev/null +++ b/node/native/src/graphql/constants.rs @@ -0,0 +1,50 @@ +use juniper::GraphQLObject; +use openmina_core::{consensus::ConsensusConstants, constants::ConstraintConstants}; + +use super::ConversionError; + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLGenesisConstants { + pub genesis_timestamp: String, + pub coinbase: String, + pub account_creation_fee: String, +} + +impl GraphQLGenesisConstants { + pub fn try_new( + constrain_constants: ConstraintConstants, + consensus_constants: ConsensusConstants, + ) -> Result { + Ok(GraphQLGenesisConstants { + genesis_timestamp: consensus_constants + .human_readable_genesis_timestamp() + .map_err(|e| ConversionError::Custom(e.to_string()))?, + coinbase: constrain_constants.coinbase_amount.to_string(), + account_creation_fee: constrain_constants.account_creation_fee.to_string(), + }) + } +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLDaemonStatus { + pub consensus_configuration: GraphQLConsensusConfiguration, +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLConsensusConfiguration { + pub epoch_duration: i32, + pub k: i32, + pub slot_duration: i32, + pub slots_per_epoch: i32, +} + +impl From for GraphQLConsensusConfiguration { + fn from(consensus_constants: ConsensusConstants) -> Self { + GraphQLConsensusConfiguration { + epoch_duration: consensus_constants.epoch_duration as i32, + k: consensus_constants.k as i32, + slot_duration: consensus_constants.slot_duration_ms as i32, + slots_per_epoch: consensus_constants.slots_per_epoch as i32, + } + } +} diff --git a/node/native/src/graphql/mod.rs b/node/native/src/graphql/mod.rs new file mode 100644 index 0000000000..067c16aa7b --- /dev/null +++ b/node/native/src/graphql/mod.rs @@ -0,0 +1,364 @@ +use std::str::FromStr; + +use juniper::{graphql_value, FieldError}; +use juniper::{EmptySubscription, GraphQLEnum, RootNode}; +use ledger::Account; +use mina_p2p_messages::v2::MinaBaseSignedCommandStableV2; +use mina_p2p_messages::v2::MinaBaseUserCommandStableV2; +use mina_p2p_messages::v2::MinaBaseZkappCommandTStableV1WireStableV1; +use mina_p2p_messages::v2::TokenIdKeyHash; +use node::rpc::RpcTransactionInjectResponse; +use node::rpc::RpcTransactionInjectedCommand; +use node::rpc::RpcTransactionStatusGetResponse; +use node::{ + account::AccountPublicKey, + rpc::{AccountQuery, RpcRequest, RpcSyncStatsGetResponse, SyncStatsQuery}, + stats::sync::SyncKind, +}; +use openmina_core::block::AppliedBlock; +use openmina_core::consensus::ConsensusConstants; +use openmina_core::constants::constraint_constants; +use openmina_node_common::rpc::RpcSender; +use warp::{Filter, Rejection, Reply}; + +pub mod account; +pub mod block; +pub mod constants; +pub mod zkapp; + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("Conversion error: {0}")] + Conversion(ConversionError), + #[error("State machine empty response")] + StateMachineEmptyResponse, + #[error("Custom: {0}")] + Custom(String), +} + +#[derive(Debug, thiserror::Error)] +pub enum ConversionError { + #[error(transparent)] + Io(#[from] std::io::Error), + #[error(transparent)] + Conversion(#[from] mina_p2p_messages::v2::conv::Error), + #[error("Wrong variant")] + WrongVariant, + #[error("SerdeJson: {0}")] + SerdeJson(#[from] serde_json::Error), + #[error("Base58Check: {0}")] + Base58Check(#[from] mina_p2p_messages::b58::FromBase58CheckError), + #[error(transparent)] + InvalidDecimalNumber(#[from] mina_p2p_messages::bigint::InvalidDecimalNumber), + #[error("Invalid bigint")] + InvalidBigInt, + #[error(transparent)] + ParseInt(#[from] std::num::ParseIntError), + #[error(transparent)] + EnumParse(#[from] strum::ParseError), + #[error(transparent)] + TryFromInt(#[from] std::num::TryFromIntError), + #[error("Missing field: {0}")] + MissingField(String), + #[error("Invalid length")] + InvalidLength, + #[error("Custom: {0}")] + Custom(String), +} + +struct Context(RpcSender); + +impl juniper::Context for Context {} + +#[derive(Clone, Copy, Debug, GraphQLEnum)] +#[allow(clippy::upper_case_acronyms)] +enum SyncStatus { + CONNECTING, + LISTENING, + OFFLINE, + BOOTSTRAP, + SYNCED, + CATCHUP, +} + +#[derive(Clone, Debug)] +struct ProtocolState { + consensus_state: ConsensusState, + blockchain_state: BlockchainState, +} + +#[juniper::graphql_object(context = Context)] +impl ProtocolState { + fn consensus_state(&self) -> &ConsensusState { + &self.consensus_state + } + + fn blockchain_state(&self) -> &BlockchainState { + &self.blockchain_state + } +} + +#[derive(Clone, Debug)] +struct ConsensusState { + block_height: i32, +} + +#[juniper::graphql_object(context = Context)] +impl ConsensusState { + fn block_height(&self) -> i32 { + self.block_height + } +} + +#[derive(Clone, Debug)] +struct BlockchainState { + snarked_ledger_hash: String, +} + +#[juniper::graphql_object(context = Context)] +impl BlockchainState { + fn snarked_ledger_hash(&self) -> &str { + &self.snarked_ledger_hash + } +} + +#[derive(Clone, Debug)] +struct BestChain { + state_hash: String, + protocol_state: ProtocolState, +} + +#[juniper::graphql_object(context = Context)] +impl BestChain { + fn state_hash(&self) -> &str { + &self.state_hash + } + + fn protocol_state(&self) -> &ProtocolState { + &self.protocol_state + } +} + +#[derive(Clone, Copy, Debug)] +struct Query; + +#[juniper::graphql_object(context = Context)] +impl Query { + async fn account( + public_key: String, + token: String, + context: &Context, + ) -> juniper::FieldResult { + let token_id = TokenIdKeyHash::from_str(&token)?; + let public_key = AccountPublicKey::from_str(&public_key)?; + let accounts: Vec = context + .0 + .oneshot_request(RpcRequest::LedgerAccountsGet( + AccountQuery::PubKeyWithTokenId(public_key, token_id), + )) + .await + .ok_or(Error::StateMachineEmptyResponse)?; + + Ok(accounts + .first() + .cloned() + .ok_or(Error::StateMachineEmptyResponse)? + .try_into()?) + } + + async fn sync_status(context: &Context) -> juniper::FieldResult { + let state: RpcSyncStatsGetResponse = context + .0 + .oneshot_request(RpcRequest::SyncStatsGet(SyncStatsQuery { limit: Some(1) })) + .await + .ok_or(Error::StateMachineEmptyResponse)?; + + if let Some(state) = state.as_ref().and_then(|s| s.first()) { + if state.synced.is_some() { + Ok(SyncStatus::SYNCED) + } else { + match &state.kind { + SyncKind::Bootstrap => Ok(SyncStatus::BOOTSTRAP), + SyncKind::Catchup => Ok(SyncStatus::CATCHUP), + } + } + } else { + Ok(SyncStatus::LISTENING) + } + } + async fn best_chain( + max_length: i32, + context: &Context, + ) -> juniper::FieldResult> { + let best_chain: Vec = context + .0 + .oneshot_request(RpcRequest::BestChain(max_length as u32)) + .await + .ok_or(Error::StateMachineEmptyResponse)?; + + Ok(best_chain + .into_iter() + .map(|v| v.try_into()) + .collect::, _>>()?) + } + + async fn daemon_status( + context: &Context, + ) -> juniper::FieldResult { + let consensus_constants: ConsensusConstants = context + .0 + .oneshot_request(RpcRequest::ConsensusConstantsGet) + .await + .ok_or(Error::StateMachineEmptyResponse)?; + Ok(constants::GraphQLDaemonStatus { + consensus_configuration: consensus_constants.into(), + }) + } + + async fn genesis_constants( + context: &Context, + ) -> juniper::FieldResult { + let consensus_constants: ConsensusConstants = context + .0 + .oneshot_request(RpcRequest::ConsensusConstantsGet) + .await + .ok_or(Error::StateMachineEmptyResponse)?; + let constraint_constants = constraint_constants(); + + Ok(constants::GraphQLGenesisConstants::try_new( + constraint_constants.clone(), + consensus_constants, + )?) + } + + async fn transaction_status( + payment: Option, + zkapp_transaction: Option, + context: &Context, + ) -> juniper::FieldResult { + if payment.is_some() && zkapp_transaction.is_some() { + return Err(Error::Custom( + "Cannot provide both payment and zkapp transaction".to_string(), + ) + .into()); + } + + let tx = if let Some(payment) = payment { + MinaBaseUserCommandStableV2::SignedCommand(MinaBaseSignedCommandStableV2::from_base64( + &payment, + )?) + } else if let Some(zkapp_transaction) = zkapp_transaction { + MinaBaseUserCommandStableV2::ZkappCommand( + MinaBaseZkappCommandTStableV1WireStableV1::from_base64(&zkapp_transaction)?, + ) + } else { + return Err(Error::Custom( + "Must provide either payment or zkapp transaction".to_string(), + ) + .into()); + }; + let res: RpcTransactionStatusGetResponse = context + .0 + .oneshot_request(RpcRequest::TransactionStatusGet(tx)) + .await + .ok_or(Error::StateMachineEmptyResponse)?; + Ok(res.to_string()) + } +} + +#[derive(Clone, Debug)] +struct Mutation; + +#[juniper::graphql_object(context = Context)] +impl Mutation { + async fn send_zkapp( + input: zkapp::SendZkappInput, + context: &Context, + ) -> juniper::FieldResult { + let res: RpcTransactionInjectResponse = context + .0 + .oneshot_request(RpcRequest::TransactionInject(vec![input.try_into()?])) + .await + .ok_or(Error::StateMachineEmptyResponse)?; + + match res { + RpcTransactionInjectResponse::Success(res) => { + let zkapp_cmd: MinaBaseUserCommandStableV2 = match res.first().cloned() { + Some(RpcTransactionInjectedCommand::Zkapp(zkapp_cmd)) => zkapp_cmd.into(), + _ => unreachable!(), + }; + Ok(zkapp_cmd.try_into()?) + } + RpcTransactionInjectResponse::Rejected(rejected) => { + let error_list = rejected + .into_iter() + .map(|(_, err)| graphql_value!({ "message": err.to_string() })) + .collect::>(); + + Err(FieldError::new( + "Transaction rejected", + graphql_value!(juniper::Value::List(error_list)), + )) + } + RpcTransactionInjectResponse::Failure(failure) => { + let error_list = failure + .into_iter() + .map(|err| graphql_value!({ "message": err.to_string() })) + .collect::>(); + + Err(FieldError::new( + "Transaction failed", + graphql_value!(juniper::Value::List(error_list)), + )) + } + } + } +} + +pub fn routes( + rpc_sernder: RpcSender, +) -> impl Filter + Clone { + let state = warp::any().map(move || Context(rpc_sernder.clone())); + let schema = RootNode::new(Query, Mutation, EmptySubscription::::new()); + let graphql_filter = juniper_warp::make_graphql_filter(schema, state.boxed()); + let graphiql_filter = juniper_warp::graphiql_filter("/graphql", None); + let playground_filter = juniper_warp::playground_filter("/graphql", None); + + (warp::post().and(warp::path("graphql")).and(graphql_filter)) + .or(warp::get() + .and(warp::path("playground")) + .and(playground_filter)) + .or(warp::get().and(warp::path("graphiql")).and(graphiql_filter)) + + // warp::get() + // .and(warp::path("graphiql")) + // .and(juniper_warp::graphiql_filter("/graphql", None)) + // .or(warp::path("graphql").and(graphql_filter)) +} + +// let routes = (warp::post() +// .and(warp::path("graphql")) +// .and(juniper_warp::make_graphql_filter( +// schema.clone(), +// warp::any().map(|| Context), +// ))) +// .or( +// warp::path("subscriptions").and(juniper_warp::subscriptions::make_ws_filter( +// schema, +// ConnectionConfig::new(Context), +// )), +// ) +// .or(warp::get() +// .and(warp::path("playground")) +// .and(juniper_warp::playground_filter( +// "/graphql", +// Some("/subscriptions"), +// ))) +// .or(warp::get() +// .and(warp::path("graphiql")) +// .and(juniper_warp::graphiql_filter( +// "/graphql", +// Some("/subscriptions"), +// ))) +// .or(homepage) +// .with(log); diff --git a/node/native/src/graphql/zkapp.rs b/node/native/src/graphql/zkapp.rs new file mode 100644 index 0000000000..76e231ce1f --- /dev/null +++ b/node/native/src/graphql/zkapp.rs @@ -0,0 +1,1838 @@ +use std::str::FromStr; + +use juniper::{GraphQLInputObject, GraphQLObject}; +use ledger::{FpExt, VerificationKey}; +use mina_p2p_messages::bigint::BigInt; +use mina_p2p_messages::list::List; +use mina_p2p_messages::pseq::PaddedSeq; +use mina_p2p_messages::string::{TokenSymbol, ZkAppUri}; +use mina_p2p_messages::v2::{ + CurrencyAmountStableV1, CurrencyBalanceStableV1, CurrencyFeeStableV1, + MinaBaseAccountUpdateAccountPreconditionStableV1, + MinaBaseAccountUpdateAuthorizationKindStableV1, MinaBaseAccountUpdateBodyEventsStableV1, + MinaBaseAccountUpdateBodyFeePayerStableV1, MinaBaseAccountUpdateBodyStableV1, + MinaBaseAccountUpdateFeePayerStableV1, MinaBaseAccountUpdateMayUseTokenStableV1, + MinaBaseAccountUpdatePreconditionsStableV1, MinaBaseAccountUpdateTStableV1, + MinaBaseAccountUpdateUpdateStableV1, MinaBaseAccountUpdateUpdateStableV1AppStateA, + MinaBaseAccountUpdateUpdateStableV1Delegate, MinaBaseAccountUpdateUpdateStableV1Permissions, + MinaBaseAccountUpdateUpdateStableV1Timing, MinaBaseAccountUpdateUpdateStableV1TokenSymbol, + MinaBaseAccountUpdateUpdateStableV1VerificationKey, + MinaBaseAccountUpdateUpdateStableV1VotingFor, MinaBaseAccountUpdateUpdateStableV1ZkappUri, + MinaBaseAccountUpdateUpdateTimingInfoStableV1, MinaBaseControlStableV2, + MinaBasePermissionsStableV2, MinaBaseReceiptChainHashStableV1, + MinaBaseSignedCommandMemoStableV1, MinaBaseUserCommandStableV2, + MinaBaseVerificationKeyWireStableV1, MinaBaseZkappCommandTStableV1WireStableV1, + MinaBaseZkappCommandTStableV1WireStableV1AccountUpdatesA, + MinaBaseZkappCommandTStableV1WireStableV1AccountUpdatesAA, + MinaBaseZkappCommandTStableV1WireStableV1AccountUpdatesAACallsA, + MinaBaseZkappPreconditionAccountStableV2, MinaBaseZkappPreconditionAccountStableV2Balance, + MinaBaseZkappPreconditionAccountStableV2BalanceA, + MinaBaseZkappPreconditionAccountStableV2Delegate, + MinaBaseZkappPreconditionAccountStableV2ProvedState, + MinaBaseZkappPreconditionAccountStableV2ReceiptChainHash, + MinaBaseZkappPreconditionAccountStableV2StateA, + MinaBaseZkappPreconditionProtocolStateEpochDataStableV1, + MinaBaseZkappPreconditionProtocolStateEpochDataStableV1EpochLedger, + MinaBaseZkappPreconditionProtocolStateEpochDataStableV1EpochSeed, + MinaBaseZkappPreconditionProtocolStateEpochDataStableV1StartCheckpoint, + MinaBaseZkappPreconditionProtocolStateStableV1, + MinaBaseZkappPreconditionProtocolStateStableV1Amount, + MinaBaseZkappPreconditionProtocolStateStableV1AmountA, + MinaBaseZkappPreconditionProtocolStateStableV1GlobalSlot, + MinaBaseZkappPreconditionProtocolStateStableV1GlobalSlotA, + MinaBaseZkappPreconditionProtocolStateStableV1Length, + MinaBaseZkappPreconditionProtocolStateStableV1LengthA, + MinaBaseZkappPreconditionProtocolStateStableV1SnarkedLedgerHash, + MinaNumbersGlobalSlotSinceGenesisMStableV1, MinaNumbersGlobalSlotSpanStableV1, + MinaStateBlockchainStateValueStableV2SignedAmount, PicklesProofProofsVerifiedMaxStableV2, + StateHash, +}; + +use node::account::AccountPublicKey; +use serde::Deserialize; + +use super::account::{GraphQLTiming, InputGraphQLTiming}; +use super::ConversionError; + +#[derive(GraphQLInputObject, Debug)] +pub struct SendZkappInput { + pub zkapp_command: InputGraphQLZkappCommand, +} + +impl TryFrom for MinaBaseUserCommandStableV2 { + type Error = ConversionError; + fn try_from(value: SendZkappInput) -> Result { + value.zkapp_command.try_into() + } +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLSendZkappResponse { + pub zkapp: GraphQLZkapp, +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLZkapp { + pub hash: String, + pub failure_reason: Option>, + /// Zkapp represented as base64 string + pub id: String, + pub zkapp_command: GraphQLZkappCommand, +} + +#[derive(GraphQLInputObject, Debug)] +pub struct InputGraphQLZkapp { + // pub hash: String, + // pub failure_reason: Option>, + /// Zkapp represented as base64 string + // pub id: String, + pub zkapp_command: InputGraphQLZkappCommand, +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLZkappCommand { + pub memo: String, + pub account_updates: Vec, + pub fee_payer: GraphQLFeePayer, +} + +#[derive(GraphQLInputObject, Debug)] +pub struct InputGraphQLZkappCommand { + pub memo: Option, + pub account_updates: Vec, + pub fee_payer: InputGraphQLFeePayer, +} + +impl TryFrom for GraphQLSendZkappResponse { + type Error = ConversionError; + fn try_from(value: MinaBaseUserCommandStableV2) -> Result { + if let MinaBaseUserCommandStableV2::ZkappCommand(zkapp) = value { + let account_updates = zkapp + .account_updates + .clone() + .into_iter() + .map(|v| v.elt.account_update.try_into()) + .collect::, _>>()?; + let res = GraphQLSendZkappResponse { + zkapp: GraphQLZkapp { + hash: zkapp.hash()?.to_string(), + failure_reason: None, + id: zkapp.to_base64()?, + zkapp_command: GraphQLZkappCommand { + memo: zkapp.memo.to_base58check(), + account_updates, + fee_payer: GraphQLFeePayer::from(zkapp.fee_payer), + }, + }, + }; + Ok(res) + } else { + Err(ConversionError::WrongVariant) + } + } +} + +impl TryFrom for MinaBaseUserCommandStableV2 { + type Error = ConversionError; + fn try_from(value: InputGraphQLZkappCommand) -> Result { + Ok(MinaBaseUserCommandStableV2::ZkappCommand( + MinaBaseZkappCommandTStableV1WireStableV1 { + fee_payer: value.fee_payer.try_into()?, + account_updates: try_tree_from_account_updates(List::from_iter( + value.account_updates, + ))?, + memo: if let Some(memo) = value.memo { + MinaBaseSignedCommandMemoStableV1::from_base58check(&memo) + } else { + let empty_memo = ledger::scan_state::transaction_logic::Memo::empty(); + MinaBaseSignedCommandMemoStableV1::from(&empty_memo) + }, + }, + )) + } +} + +/// Recursively builds a tree of account updates based on their depth. +fn try_tree_from_account_updates( + updates: List, +) -> Result, ConversionError> { + let result = + try_tree_from_account_updates_aux(updates)? + .into_iter() + .map(|update| { + let MinaBaseZkappCommandTStableV1WireStableV1AccountUpdatesAACallsA { + elt, + stack_hash, + } = update; + let MinaBaseZkappCommandTStableV1WireStableV1AccountUpdatesAA { + account_update, + account_update_digest, + calls, + } = *elt; + let elt = MinaBaseZkappCommandTStableV1WireStableV1AccountUpdatesAA { + account_update, + account_update_digest, + calls, + }; + MinaBaseZkappCommandTStableV1WireStableV1AccountUpdatesA { elt, stack_hash } + }) + .collect(); + Ok(result) +} + +fn try_tree_from_account_updates_aux( + updates: List, +) -> Result, ConversionError> +{ + let mut result = List::new(); + let mut iter = updates.into_iter().peekable(); + + while let Some(account_update) = iter.next() { + let depth = account_update.body.call_depth; + let mut children = List::new(); + + while let Some(next_p) = iter.peek() { + if next_p.body.call_depth > depth { + // unwrap cannot fail, we just peeked it + children.push_back(iter.next().unwrap()); + } else { + break; + } + } + + let calls = try_tree_from_account_updates_aux(children)?; + + result.push_back( + MinaBaseZkappCommandTStableV1WireStableV1AccountUpdatesAACallsA { + elt: Box::new(MinaBaseZkappCommandTStableV1WireStableV1AccountUpdatesAA { + account_update: account_update.try_into()?, // FIXME: remove unwrap + account_update_digest: (), + calls, + }), + stack_hash: (), + }, + ); + } + + Ok(result) +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLFeePayer { + pub body: GraphQLFeePayerBody, + pub authorization: String, +} + +#[derive(GraphQLInputObject, Debug)] +pub struct InputGraphQLFeePayer { + pub body: InputGraphQLFeePayerBody, + pub authorization: String, +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLFeePayerBody { + pub public_key: String, + pub fee: String, + pub valid_until: Option, + pub nonce: String, +} + +#[derive(GraphQLInputObject, Debug)] +pub struct InputGraphQLFeePayerBody { + pub public_key: String, + pub fee: String, + pub valid_until: Option, + pub nonce: String, +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLAccountUpdate { + pub body: GraphQLAccountUpdateBody, + pub authorization: GraphQLAuthorization, +} + +#[derive(GraphQLInputObject, Debug)] +pub struct InputGraphQLAccountUpdate { + pub body: InputGraphQLAccountUpdateBody, + pub authorization: InputGraphQLAuthorization, +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLAuthorization { + pub proof: Option, + pub signature: Option, +} + +#[derive(GraphQLInputObject, Debug)] +pub struct InputGraphQLAuthorization { + pub proof: Option, + pub signature: Option, +} + +impl TryFrom for GraphQLAuthorization { + type Error = ConversionError; + + fn try_from(value: MinaBaseControlStableV2) -> Result { + let auth = match value { + MinaBaseControlStableV2::Signature(signature) => GraphQLAuthorization { + proof: None, + signature: Some(signature.to_string()), + }, + MinaBaseControlStableV2::Proof(proof) => GraphQLAuthorization { + proof: Some( + serde_json::to_string_pretty(&proof)? + .trim_matches('"') + .to_string(), + ), + signature: None, + }, + MinaBaseControlStableV2::NoneGiven => GraphQLAuthorization { + proof: None, + signature: None, + }, + }; + Ok(auth) + } +} + +impl TryFrom for MinaBaseControlStableV2 { + type Error = ConversionError; + + fn try_from(value: InputGraphQLAuthorization) -> Result { + match (value.signature, value.proof) { + (Some(signature), None) => { + // Handle signature case + Ok(MinaBaseControlStableV2::Signature(signature.parse()?)) + } + (None, Some(proof)) => { + // Handle proof case + let proof = PicklesProofProofsVerifiedMaxStableV2::deserialize( + serde_json::Value::String(proof), + )?; + Ok(MinaBaseControlStableV2::Proof(Box::new(proof))) + } + _ => Err(ConversionError::Custom( + "Either signature or proof must be provided, but not both".into(), + )), + } + } +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLAccountUpdateBody { + pub public_key: String, + pub token_id: String, + pub use_full_commitment: bool, + pub increment_nonce: bool, + pub update: GraphQLAccountUpdateUpdate, + pub balance_change: GraphQLBalanceChange, + pub events: Vec>, + pub actions: Vec>, + pub call_data: String, + pub call_depth: i32, + pub preconditions: GraphQLPreconditions, + pub may_use_token: GraphQLMayUseToken, + pub authorization_kind: GraphQLAuthorizationKind, + pub implicit_account_creation_fee: bool, +} + +#[derive(GraphQLInputObject, Debug)] +pub struct InputGraphQLAccountUpdateBody { + pub public_key: String, + pub token_id: String, + pub use_full_commitment: bool, + pub increment_nonce: bool, + pub update: InputGraphQLAccountUpdateUpdate, + pub balance_change: InputGraphQLBalanceChange, + pub events: Vec>, + pub actions: Vec>, + pub call_data: String, + pub call_depth: i32, + pub preconditions: InputGraphQLPreconditions, + pub may_use_token: InputGraphQLMayUseToken, + pub authorization_kind: InputGraphQLAuthorizationKind, + pub implicit_account_creation_fee: bool, +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLAuthorizationKind { + pub is_signed: bool, + pub is_proved: bool, + pub verification_key_hash: Option, +} + +#[derive(GraphQLInputObject, Debug)] +pub struct InputGraphQLAuthorizationKind { + pub is_signed: bool, + pub is_proved: bool, + pub verification_key_hash: Option, +} + +impl From for GraphQLAuthorizationKind { + fn from(value: MinaBaseAccountUpdateAuthorizationKindStableV1) -> Self { + match value { + MinaBaseAccountUpdateAuthorizationKindStableV1::Signature => GraphQLAuthorizationKind { + is_signed: true, + is_proved: false, + verification_key_hash: None, + }, + MinaBaseAccountUpdateAuthorizationKindStableV1::Proof(proof) => { + GraphQLAuthorizationKind { + is_signed: false, + is_proved: true, + verification_key_hash: Some(proof.to_decimal()), + } + } + MinaBaseAccountUpdateAuthorizationKindStableV1::NoneGiven => GraphQLAuthorizationKind { + is_signed: false, + is_proved: false, + verification_key_hash: None, + }, + } + } +} + +impl TryFrom for MinaBaseAccountUpdateAuthorizationKindStableV1 { + type Error = ConversionError; + fn try_from(value: InputGraphQLAuthorizationKind) -> Result { + if value.is_signed { + return Ok(MinaBaseAccountUpdateAuthorizationKindStableV1::Signature); + } + + if value.is_proved { + match &value.verification_key_hash { + Some(vk_hash) => { + let big_int = BigInt::from_decimal(vk_hash)?; + return Ok(MinaBaseAccountUpdateAuthorizationKindStableV1::Proof( + big_int, + )); + } + None => { + return Err(ConversionError::MissingField( + "verification_key_hash".to_string(), + )); + } + } + } + + Ok(MinaBaseAccountUpdateAuthorizationKindStableV1::NoneGiven) + } +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLMayUseToken { + pub parents_own_token: bool, + pub inherit_from_parent: bool, +} + +#[derive(GraphQLInputObject, Debug)] +pub struct InputGraphQLMayUseToken { + pub parents_own_token: bool, + pub inherit_from_parent: bool, +} + +impl From for GraphQLMayUseToken { + fn from(value: MinaBaseAccountUpdateMayUseTokenStableV1) -> Self { + match value { + MinaBaseAccountUpdateMayUseTokenStableV1::ParentsOwnToken => GraphQLMayUseToken { + parents_own_token: true, + inherit_from_parent: false, + }, + MinaBaseAccountUpdateMayUseTokenStableV1::InheritFromParent => GraphQLMayUseToken { + parents_own_token: false, + inherit_from_parent: true, + }, + MinaBaseAccountUpdateMayUseTokenStableV1::No => GraphQLMayUseToken { + parents_own_token: false, + inherit_from_parent: false, + }, + } + } +} + +impl From for MinaBaseAccountUpdateMayUseTokenStableV1 { + fn from(value: InputGraphQLMayUseToken) -> Self { + if value.parents_own_token { + MinaBaseAccountUpdateMayUseTokenStableV1::ParentsOwnToken + } else if value.inherit_from_parent { + MinaBaseAccountUpdateMayUseTokenStableV1::InheritFromParent + } else { + MinaBaseAccountUpdateMayUseTokenStableV1::No + } + } +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLEvent { + pub event: String, + pub data: String, +} + +#[derive(GraphQLInputObject, Debug)] +pub struct InputGraphQLEvent { + pub event: String, + pub data: String, +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLAction { + pub action: String, + pub data: String, +} + +#[derive(GraphQLInputObject, Debug)] +pub struct InputGraphQLAction { + pub action: String, + pub data: String, +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLPreconditions { + pub network: GraphQLPreconditionsNetwork, + pub account: GraphQLPreconditionsAccount, + pub valid_while: Option, +} + +#[derive(GraphQLInputObject, Debug)] +pub struct InputGraphQLPreconditions { + pub network: InputGraphQLPreconditionsNetwork, + pub account: InputGraphQLPreconditionsAccount, + pub valid_while: Option, +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLPreconditionsAccount { + pub balance: Option, + pub nonce: Option, + pub receipt_chain_hash: Option, + pub delegate: Option, + pub state: Vec>, + pub action_state: Option, + pub proved_state: Option, + pub is_new: Option, +} + +#[derive(GraphQLInputObject, Debug)] +pub struct InputGraphQLPreconditionsAccount { + pub balance: Option, + pub nonce: Option, + pub receipt_chain_hash: Option, + pub delegate: Option, + pub state: Vec>, + pub action_state: Option, + pub proved_state: Option, + pub is_new: Option, +} + +impl From for GraphQLPreconditionsAccount { + fn from(value: MinaBaseAccountUpdateAccountPreconditionStableV1) -> Self { + Self { + balance: if let MinaBaseZkappPreconditionAccountStableV2Balance::Check(v) = + value.0.balance + { + Some(GraphQLPreconditionsNetworkBounds { + upper: v.upper.as_u64().to_string(), + lower: v.lower.as_u64().to_string(), + }) + } else { + None + }, + nonce: if let MinaBaseZkappPreconditionProtocolStateStableV1Length::Check(v) = + value.0.nonce + { + Some(GraphQLPreconditionsNetworkBounds { + upper: v.upper.as_u32().to_string(), + lower: v.lower.as_u32().to_string(), + }) + } else { + None + }, + receipt_chain_hash: + if let MinaBaseZkappPreconditionAccountStableV2ReceiptChainHash::Check(v) = + value.0.receipt_chain_hash + { + Some(v.to_decimal()) + } else { + None + }, + delegate: if let MinaBaseZkappPreconditionAccountStableV2Delegate::Check(v) = + value.0.delegate + { + Some(v.to_string()) + } else { + None + }, + state: value + .0 + .state + .clone() + .iter() + .map(|v| { + if let MinaBaseZkappPreconditionAccountStableV2StateA::Check(state_value) = v { + Some(state_value.to_decimal()) + } else { + None + } + }) + .collect(), + action_state: if let MinaBaseZkappPreconditionAccountStableV2StateA::Check(value) = + value.0.action_state + { + Some(value.to_decimal()) + } else { + None + }, + proved_state: if let MinaBaseZkappPreconditionAccountStableV2ProvedState::Check(v) = + value.0.proved_state + { + Some(v) + } else { + None + }, + is_new: if let MinaBaseZkappPreconditionAccountStableV2ProvedState::Check(v) = + value.0.is_new + { + Some(v) + } else { + None + }, + } + } +} + +impl TryFrom + for MinaBaseAccountUpdateAccountPreconditionStableV1 +{ + type Error = ConversionError; + fn try_from(value: InputGraphQLPreconditionsAccount) -> Result { + let state: Result, _> = value + .state + .iter() + .map(|v| { + if let Some(state) = v { + BigInt::from_decimal(state) + .map(MinaBaseZkappPreconditionAccountStableV2StateA::Check) + } else { + Ok(MinaBaseZkappPreconditionAccountStableV2StateA::Ignore) + } + }) + .collect(); + + let state = state?; + Ok(Self(MinaBaseZkappPreconditionAccountStableV2 { + balance: if let Some(balance) = value.balance { + MinaBaseZkappPreconditionAccountStableV2Balance::Check( + MinaBaseZkappPreconditionAccountStableV2BalanceA { + lower: CurrencyBalanceStableV1(CurrencyAmountStableV1( + balance.lower.parse::()?.into(), + )), + upper: CurrencyBalanceStableV1(CurrencyAmountStableV1( + balance.upper.parse::()?.into(), + )), + }, + ) + } else { + MinaBaseZkappPreconditionAccountStableV2Balance::Ignore + }, + nonce: if let Some(nonce) = value.nonce { + MinaBaseZkappPreconditionProtocolStateStableV1Length::Check( + MinaBaseZkappPreconditionProtocolStateStableV1LengthA { + lower: (nonce.lower.parse::()?).into(), + upper: (nonce.upper.parse::()?).into(), + }, + ) + } else { + MinaBaseZkappPreconditionProtocolStateStableV1Length::Ignore + }, + receipt_chain_hash: if let Some(receipt_chain_hash) = value.receipt_chain_hash { + MinaBaseZkappPreconditionAccountStableV2ReceiptChainHash::Check( + MinaBaseReceiptChainHashStableV1(BigInt::from_decimal(&receipt_chain_hash)?), + ) + } else { + MinaBaseZkappPreconditionAccountStableV2ReceiptChainHash::Ignore + }, + delegate: if let Some(delegate) = value.delegate { + MinaBaseZkappPreconditionAccountStableV2Delegate::Check( + AccountPublicKey::from_str(&delegate)?.into(), + ) + } else { + MinaBaseZkappPreconditionAccountStableV2Delegate::Ignore + }, + state: PaddedSeq( + state + .try_into() + .map_err(|_| ConversionError::InvalidLength)?, + ), + action_state: if let Some(action_state) = value.action_state { + MinaBaseZkappPreconditionAccountStableV2StateA::Check(BigInt::from_decimal( + &action_state, + )?) + } else { + MinaBaseZkappPreconditionAccountStableV2StateA::Ignore + }, + proved_state: if let Some(proved_state) = value.proved_state { + MinaBaseZkappPreconditionAccountStableV2ProvedState::Check(proved_state) + } else { + MinaBaseZkappPreconditionAccountStableV2ProvedState::Ignore + }, + is_new: if let Some(is_new) = value.is_new { + MinaBaseZkappPreconditionAccountStableV2ProvedState::Check(is_new) + } else { + MinaBaseZkappPreconditionAccountStableV2ProvedState::Ignore + }, + })) + } +} +#[derive(GraphQLObject, Debug)] +pub struct GraphQLPreconditionsNetwork { + pub snarked_ledger_hash: Option, + pub blockchain_length: Option, + pub min_window_density: Option, + pub total_currency: Option, + pub global_slot_since_genesis: Option, + pub staking_epoch_data: GraphQLPreconditionsNetworkEpochData, + pub next_epoch_data: GraphQLPreconditionsNetworkEpochData, +} + +#[derive(GraphQLInputObject, Debug)] +pub struct InputGraphQLPreconditionsNetwork { + pub snarked_ledger_hash: Option, + pub blockchain_length: Option, + pub min_window_density: Option, + pub total_currency: Option, + pub global_slot_since_genesis: Option, + pub staking_epoch_data: InputGraphQLPreconditionsNetworkEpochData, + pub next_epoch_data: InputGraphQLPreconditionsNetworkEpochData, +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLPreconditionsNetworkEpochData { + pub ledger: GraphQLPreconditionsNetworkLedger, + pub seed: Option, + pub start_checkpoint: Option, + pub lock_checkpoint: Option, + pub epoch_length: Option, +} + +#[derive(GraphQLInputObject, Debug)] +pub struct InputGraphQLPreconditionsNetworkEpochData { + pub ledger: InputGraphQLPreconditionsNetworkLedger, + pub seed: Option, + pub start_checkpoint: Option, + pub lock_checkpoint: Option, + pub epoch_length: Option, +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLPreconditionsNetworkLedger { + pub hash: Option, + pub total_currency: Option, +} + +#[derive(GraphQLInputObject, Debug)] +pub struct InputGraphQLPreconditionsNetworkLedger { + pub hash: Option, + pub total_currency: Option, +} +#[derive(GraphQLObject, Debug)] +pub struct GraphQLPreconditionsNetworkBounds { + pub upper: String, + pub lower: String, +} + +#[derive(GraphQLInputObject, Debug)] +pub struct InputGraphQLPreconditionsNetworkBounds { + pub upper: String, + pub lower: String, +} + +impl From + for GraphQLPreconditionsNetworkEpochData +{ + fn from(value: MinaBaseZkappPreconditionProtocolStateEpochDataStableV1) -> Self { + Self { + ledger: GraphQLPreconditionsNetworkLedger::from(value.ledger), + seed: if let MinaBaseZkappPreconditionProtocolStateEpochDataStableV1EpochSeed::Check(v) = value.seed { + Some(v.to_string()) + } else { + None + }, + start_checkpoint: if let MinaBaseZkappPreconditionProtocolStateEpochDataStableV1StartCheckpoint::Check(v) = value.start_checkpoint { + Some(v.to_string()) + } else { + None + }, + lock_checkpoint: if let MinaBaseZkappPreconditionProtocolStateEpochDataStableV1StartCheckpoint::Check(v) = value.lock_checkpoint { + Some(v.to_string()) + } else { + None + }, + epoch_length: if let MinaBaseZkappPreconditionProtocolStateStableV1Length::Check(v) = value.epoch_length { + Some(GraphQLPreconditionsNetworkBounds { + upper: v.upper.as_u32().to_string(), + lower: v.lower.as_u32().to_string(), + }) + } else { + None + }, + } + } +} + +impl TryFrom + for MinaBaseZkappPreconditionProtocolStateEpochDataStableV1 +{ + type Error = ConversionError; + fn try_from(value: InputGraphQLPreconditionsNetworkEpochData) -> Result { + Ok(Self { + ledger: value.ledger.try_into()?, + seed: if let Some(seed) = value.seed { + MinaBaseZkappPreconditionProtocolStateEpochDataStableV1EpochSeed::Check( + seed.parse()?, + ) + } else { + MinaBaseZkappPreconditionProtocolStateEpochDataStableV1EpochSeed::Ignore + }, + start_checkpoint: if let Some(start_checkpoint) = value.start_checkpoint { + MinaBaseZkappPreconditionProtocolStateEpochDataStableV1StartCheckpoint::Check( + start_checkpoint.parse()?, + ) + } else { + MinaBaseZkappPreconditionProtocolStateEpochDataStableV1StartCheckpoint::Ignore + }, + lock_checkpoint: if let Some(lock_checkpoint) = value.lock_checkpoint { + MinaBaseZkappPreconditionProtocolStateEpochDataStableV1StartCheckpoint::Check( + lock_checkpoint.parse()?, + ) + } else { + MinaBaseZkappPreconditionProtocolStateEpochDataStableV1StartCheckpoint::Ignore + }, + epoch_length: if let Some(epoch_length) = value.epoch_length { + MinaBaseZkappPreconditionProtocolStateStableV1Length::Check( + MinaBaseZkappPreconditionProtocolStateStableV1LengthA { + lower: (epoch_length.lower.parse::()?).into(), + upper: (epoch_length.upper.parse::()?).into(), + }, + ) + } else { + MinaBaseZkappPreconditionProtocolStateStableV1Length::Ignore + }, + }) + } +} +impl From + for GraphQLPreconditionsNetworkLedger +{ + fn from(value: MinaBaseZkappPreconditionProtocolStateEpochDataStableV1EpochLedger) -> Self { + Self { + hash: if let MinaBaseZkappPreconditionProtocolStateStableV1SnarkedLedgerHash::Check(v) = + value.hash + { + Some(v.to_string()) + } else { + None + }, + total_currency: if let MinaBaseZkappPreconditionProtocolStateStableV1Amount::Check(v) = + value.total_currency + { + Some(GraphQLPreconditionsNetworkBounds { + upper: v.upper.as_u64().to_string(), + lower: v.lower.as_u64().to_string(), + }) + } else { + None + }, + } + } +} + +impl TryFrom + for MinaBaseZkappPreconditionProtocolStateEpochDataStableV1EpochLedger +{ + type Error = ConversionError; + fn try_from(value: InputGraphQLPreconditionsNetworkLedger) -> Result { + Ok(Self { + hash: if let Some(hash) = value.hash { + MinaBaseZkappPreconditionProtocolStateStableV1SnarkedLedgerHash::Check( + hash.parse()?, + ) + } else { + MinaBaseZkappPreconditionProtocolStateStableV1SnarkedLedgerHash::Ignore + }, + total_currency: if let Some(total_currency) = value.total_currency { + MinaBaseZkappPreconditionProtocolStateStableV1Amount::Check( + MinaBaseZkappPreconditionProtocolStateStableV1AmountA { + lower: CurrencyAmountStableV1( + (total_currency.lower.parse::()?).into(), + ), + upper: CurrencyAmountStableV1( + (total_currency.upper.parse::()?).into(), + ), + }, + ) + } else { + MinaBaseZkappPreconditionProtocolStateStableV1Amount::Ignore + }, + }) + } +} + +impl From for GraphQLPreconditionsNetwork { + fn from(value: MinaBaseZkappPreconditionProtocolStateStableV1) -> Self { + Self { + snarked_ledger_hash: + if let MinaBaseZkappPreconditionProtocolStateStableV1SnarkedLedgerHash::Check(v) = + value.snarked_ledger_hash + { + Some(v.to_string()) + } else { + None + }, + blockchain_length: if let MinaBaseZkappPreconditionProtocolStateStableV1Length::Check( + v, + ) = value.blockchain_length + { + Some(GraphQLPreconditionsNetworkBounds { + upper: v.upper.as_u32().to_string(), + lower: v.lower.as_u32().to_string(), + }) + } else { + None + }, + min_window_density: if let MinaBaseZkappPreconditionProtocolStateStableV1Length::Check( + v, + ) = value.min_window_density + { + Some(GraphQLPreconditionsNetworkBounds { + upper: v.upper.as_u32().to_string(), + lower: v.lower.as_u32().to_string(), + }) + } else { + None + }, + total_currency: if let MinaBaseZkappPreconditionProtocolStateStableV1Amount::Check(v) = + value.total_currency + { + Some(GraphQLPreconditionsNetworkBounds { + upper: v.upper.as_u64().to_string(), + lower: v.lower.as_u64().to_string(), + }) + } else { + None + }, + global_slot_since_genesis: + if let MinaBaseZkappPreconditionProtocolStateStableV1GlobalSlot::Check(v) = + value.global_slot_since_genesis + { + Some(GraphQLPreconditionsNetworkBounds { + upper: v.upper.as_u32().to_string(), + lower: v.lower.as_u32().to_string(), + }) + } else { + None + }, + staking_epoch_data: GraphQLPreconditionsNetworkEpochData::from( + value.staking_epoch_data, + ), + next_epoch_data: GraphQLPreconditionsNetworkEpochData::from(value.next_epoch_data), + } + } +} + +impl TryFrom for MinaBaseZkappPreconditionProtocolStateStableV1 { + type Error = ConversionError; + fn try_from(value: InputGraphQLPreconditionsNetwork) -> Result { + Ok(Self { + snarked_ledger_hash: if let Some(snarked_ledger_hash) = value.snarked_ledger_hash { + MinaBaseZkappPreconditionProtocolStateStableV1SnarkedLedgerHash::Check( + snarked_ledger_hash.parse()?, + ) + } else { + MinaBaseZkappPreconditionProtocolStateStableV1SnarkedLedgerHash::Ignore + }, + blockchain_length: if let Some(blockchain_length) = value.blockchain_length { + MinaBaseZkappPreconditionProtocolStateStableV1Length::Check( + MinaBaseZkappPreconditionProtocolStateStableV1LengthA { + lower: (blockchain_length.lower.parse::()?).into(), + upper: (blockchain_length.upper.parse::()?).into(), + }, + ) + } else { + MinaBaseZkappPreconditionProtocolStateStableV1Length::Ignore + }, + min_window_density: if let Some(min_window_density) = value.min_window_density { + MinaBaseZkappPreconditionProtocolStateStableV1Length::Check( + MinaBaseZkappPreconditionProtocolStateStableV1LengthA { + lower: (min_window_density.lower.parse::()?).into(), + upper: (min_window_density.upper.parse::()?).into(), + }, + ) + } else { + MinaBaseZkappPreconditionProtocolStateStableV1Length::Ignore + }, + total_currency: if let Some(total_currency) = value.total_currency { + MinaBaseZkappPreconditionProtocolStateStableV1Amount::Check( + MinaBaseZkappPreconditionProtocolStateStableV1AmountA { + lower: CurrencyAmountStableV1( + (total_currency.lower.parse::()?).into(), + ), + upper: CurrencyAmountStableV1( + (total_currency.upper.parse::()?).into(), + ), + }, + ) + } else { + MinaBaseZkappPreconditionProtocolStateStableV1Amount::Ignore + }, + global_slot_since_genesis: if let Some(global_slot_since_genesis) = + value.global_slot_since_genesis + { + MinaBaseZkappPreconditionProtocolStateStableV1GlobalSlot::Check( + MinaBaseZkappPreconditionProtocolStateStableV1GlobalSlotA { + lower: MinaNumbersGlobalSlotSinceGenesisMStableV1::SinceGenesis( + (global_slot_since_genesis.lower.parse::()?).into(), + ), + upper: MinaNumbersGlobalSlotSinceGenesisMStableV1::SinceGenesis( + (global_slot_since_genesis.upper.parse::()?).into(), + ), + }, + ) + } else { + MinaBaseZkappPreconditionProtocolStateStableV1GlobalSlot::Ignore + }, + staking_epoch_data: value.staking_epoch_data.try_into()?, + next_epoch_data: value.next_epoch_data.try_into()?, + }) + } +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLAccountUpdateUpdate { + pub app_state: Vec>, + pub delegate: Option, + pub verification_key: Option, + pub permissions: Option, + pub zkapp_uri: Option, + pub token_symbol: Option, + pub timing: Option, + pub voting_for: Option, +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLVerificationKey { + pub data: String, + pub hash: String, +} + +#[derive(GraphQLInputObject, Debug)] +pub struct InputGraphQLAccountUpdateUpdate { + pub app_state: Vec>, + pub delegate: Option, + pub verification_key: Option, + pub permissions: Option, + pub zkapp_uri: Option, + pub token_symbol: Option, + pub timing: Option, + pub voting_for: Option, +} + +#[derive(GraphQLInputObject, Debug)] +pub struct InputGraphQLVerificationKey { + pub data: String, + pub hash: String, +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLAccountUpdateUpdatePermissions { + pub edit_state: String, + pub access: String, + pub send: String, + pub receive: String, + pub set_delegate: String, + pub set_permissions: String, + pub set_verification_key: GraphQLSetVerificationKeyPermissions, + pub set_zkapp_uri: String, + pub edit_action_state: String, + pub set_token_symbol: String, + pub set_timing: String, + pub set_voting_for: String, + pub increment_nonce: String, +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLSetVerificationKeyPermissions { + pub auth: String, + pub txn_version: String, +} + +#[derive(GraphQLInputObject, Debug)] +pub struct InputGraphQLAccountUpdateUpdatePermissions { + pub edit_state: String, + pub access: String, + pub send: String, + pub receive: String, + pub set_delegate: String, + pub set_permissions: String, + pub set_verification_key: InputGraphQLSetVerificationKeyPermissions, + pub set_zkapp_uri: String, + pub edit_action_state: String, + pub set_token_symbol: String, + pub set_timing: String, + pub set_voting_for: String, + pub increment_nonce: String, +} + +#[derive(GraphQLInputObject, Debug)] +pub struct InputGraphQLSetVerificationKeyPermissions { + pub auth: String, + pub txn_version: String, +} + +impl From for GraphQLAccountUpdateUpdatePermissions { + fn from(value: MinaBasePermissionsStableV2) -> Self { + Self { + edit_state: value.edit_state.to_string(), + access: value.access.to_string(), + send: value.send.to_string(), + receive: value.receive.to_string(), + set_delegate: value.set_delegate.to_string(), + set_permissions: value.set_permissions.to_string(), + set_verification_key: GraphQLSetVerificationKeyPermissions { + auth: value.set_verification_key.0.to_string(), + txn_version: value.set_verification_key.1.as_u32().to_string(), + }, + set_zkapp_uri: value.set_zkapp_uri.to_string(), + edit_action_state: value.edit_action_state.to_string(), + set_token_symbol: value.set_token_symbol.to_string(), + set_timing: value.set_timing.to_string(), + set_voting_for: value.set_voting_for.to_string(), + increment_nonce: value.increment_nonce.to_string(), + } + } +} + +impl TryFrom for MinaBasePermissionsStableV2 { + type Error = ConversionError; + fn try_from(value: InputGraphQLAccountUpdateUpdatePermissions) -> Result { + Ok(Self { + edit_state: value.edit_state.parse()?, + access: value.access.parse()?, + send: value.send.parse()?, + receive: value.receive.parse()?, + set_delegate: value.set_delegate.parse()?, + set_permissions: value.set_permissions.parse()?, + set_verification_key: ( + value.set_verification_key.auth.parse()?, + value + .set_verification_key + .txn_version + .parse::()? + .into(), + ), + set_zkapp_uri: value.set_zkapp_uri.parse()?, + edit_action_state: value.edit_action_state.parse()?, + set_token_symbol: value.set_token_symbol.parse()?, + set_timing: value.set_timing.parse()?, + set_voting_for: value.set_voting_for.parse()?, + increment_nonce: value.increment_nonce.parse()?, + }) + } +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLBalanceChange { + pub magnitude: String, + pub sgn: String, +} + +#[derive(GraphQLInputObject, Debug)] +pub struct InputGraphQLBalanceChange { + pub magnitude: String, + pub sgn: String, +} + +#[derive(GraphQLObject, Debug)] +pub struct GraphQLFailureReason { + pub index: String, + pub failures: Vec, +} + +impl From for GraphQLBalanceChange { + fn from(value: MinaStateBlockchainStateValueStableV2SignedAmount) -> Self { + Self { + magnitude: value.magnitude.as_u64().to_string(), + sgn: value.sgn.to_string(), + } + } +} + +impl TryFrom for MinaStateBlockchainStateValueStableV2SignedAmount { + type Error = ConversionError; + fn try_from(value: InputGraphQLBalanceChange) -> Result { + Ok(Self { + magnitude: CurrencyAmountStableV1(value.magnitude.parse::()?.into()), + sgn: value + .sgn + .parse() + .map_err(|_| ConversionError::WrongVariant)?, + }) + } +} + +impl From for GraphQLPreconditions { + fn from(value: MinaBaseAccountUpdatePreconditionsStableV1) -> Self { + Self { + network: GraphQLPreconditionsNetwork::from(value.network), + account: GraphQLPreconditionsAccount::from(value.account), + valid_while: if let MinaBaseZkappPreconditionProtocolStateStableV1GlobalSlot::Check(v) = + value.valid_while + { + Some(GraphQLPreconditionsNetworkBounds { + upper: v.upper.as_u32().to_string(), + lower: v.lower.as_u32().to_string(), + }) + } else { + None + }, + } + } +} + +impl TryFrom for MinaBaseAccountUpdatePreconditionsStableV1 { + type Error = ConversionError; + fn try_from(value: InputGraphQLPreconditions) -> Result { + Ok(Self { + network: value.network.try_into()?, + account: value.account.try_into()?, + valid_while: if let Some(v) = value.valid_while { + MinaBaseZkappPreconditionProtocolStateStableV1GlobalSlot::Check( + MinaBaseZkappPreconditionProtocolStateStableV1GlobalSlotA { + upper: MinaNumbersGlobalSlotSinceGenesisMStableV1::SinceGenesis( + (v.upper.parse::()?).into(), + ), + lower: MinaNumbersGlobalSlotSinceGenesisMStableV1::SinceGenesis( + (v.lower.parse::()?).into(), + ), + }, + ) + } else { + MinaBaseZkappPreconditionProtocolStateStableV1GlobalSlot::Ignore + }, + }) + } +} + +impl TryFrom for GraphQLVerificationKey { + type Error = ConversionError; + + fn try_from(value: MinaBaseVerificationKeyWireStableV1) -> Result { + Ok(Self { + data: value.to_base64()?, + hash: VerificationKey::try_from(&value) + .map_err(|_| ConversionError::InvalidBigInt)? + .hash() + .to_decimal(), + }) + } +} + +impl TryFrom for MinaBaseVerificationKeyWireStableV1 { + type Error = ConversionError; + + fn try_from(value: InputGraphQLVerificationKey) -> Result { + Ok(Self::from_base64(&value.data)?) + } +} + +impl TryFrom for GraphQLAccountUpdateUpdate { + type Error = ConversionError; + + fn try_from(value: MinaBaseAccountUpdateUpdateStableV1) -> Result { + Ok(Self { + app_state: value + .app_state + .0 + .into_iter() + .map(|v| { + if let MinaBaseAccountUpdateUpdateStableV1AppStateA::Set(value) = v { + Some(value.to_decimal()) + } else { + None + } + }) + .collect(), + delegate: if let MinaBaseAccountUpdateUpdateStableV1Delegate::Set(v) = value.delegate { + Some(v.to_string()) + } else { + None + }, + verification_key: if let MinaBaseAccountUpdateUpdateStableV1VerificationKey::Set(v) = + value.verification_key + { + Some(GraphQLVerificationKey::try_from(*v)?) + } else { + None + }, + permissions: if let MinaBaseAccountUpdateUpdateStableV1Permissions::Set(v) = + value.permissions + { + Some(GraphQLAccountUpdateUpdatePermissions::from(*v)) + } else { + None + }, + zkapp_uri: if let MinaBaseAccountUpdateUpdateStableV1ZkappUri::Set(v) = value.zkapp_uri + { + Some(v.to_string()) + } else { + None + }, + token_symbol: if let MinaBaseAccountUpdateUpdateStableV1TokenSymbol::Set(v) = + value.token_symbol + { + Some(v.to_string()) + } else { + None + }, + timing: if let MinaBaseAccountUpdateUpdateStableV1Timing::Set(v) = value.timing { + Some(GraphQLTiming::from(*v)) + } else { + None + }, + voting_for: if let MinaBaseAccountUpdateUpdateStableV1VotingFor::Set(v) = + value.voting_for + { + Some(v.to_string()) + } else { + None + }, + }) + } +} + +impl TryFrom for MinaBaseAccountUpdateUpdateStableV1 { + type Error = ConversionError; + fn try_from(value: InputGraphQLAccountUpdateUpdate) -> Result { + let app_state: Vec<_> = value + .app_state + .iter() + .map(|v| { + if let Some(v) = v { + Ok(MinaBaseAccountUpdateUpdateStableV1AppStateA::Set( + BigInt::from_decimal(v)?, + )) + } else { + Ok(MinaBaseAccountUpdateUpdateStableV1AppStateA::Keep) + } + }) + .collect::, ConversionError>>()?; + Ok(Self { + app_state: PaddedSeq( + app_state + .try_into() + .map_err(|_| ConversionError::InvalidLength)?, + ), + delegate: if let Some(delegate) = value.delegate { + MinaBaseAccountUpdateUpdateStableV1Delegate::Set( + AccountPublicKey::from_str(&delegate)?.into(), + ) + } else { + MinaBaseAccountUpdateUpdateStableV1Delegate::Keep + }, + verification_key: if let Some(vk) = value.verification_key { + MinaBaseAccountUpdateUpdateStableV1VerificationKey::Set(Box::new( + MinaBaseVerificationKeyWireStableV1::try_from(vk)?, + )) + } else { + MinaBaseAccountUpdateUpdateStableV1VerificationKey::Keep + }, + permissions: if let Some(permissions) = value.permissions { + MinaBaseAccountUpdateUpdateStableV1Permissions::Set(Box::new( + MinaBasePermissionsStableV2::try_from(permissions)?, + )) + } else { + MinaBaseAccountUpdateUpdateStableV1Permissions::Keep + }, + zkapp_uri: if let Some(zkapp_uri) = value.zkapp_uri { + MinaBaseAccountUpdateUpdateStableV1ZkappUri::Set(ZkAppUri::from(zkapp_uri.as_str())) + } else { + MinaBaseAccountUpdateUpdateStableV1ZkappUri::Keep + }, + token_symbol: if let Some(token_symbol) = value.token_symbol { + MinaBaseAccountUpdateUpdateStableV1TokenSymbol::Set(TokenSymbol::from( + token_symbol.as_str(), + )) + } else { + MinaBaseAccountUpdateUpdateStableV1TokenSymbol::Keep + }, + timing: if let Some(timing) = value.timing { + MinaBaseAccountUpdateUpdateStableV1Timing::Set(Box::new( + MinaBaseAccountUpdateUpdateTimingInfoStableV1::try_from(timing)?, + )) + } else { + MinaBaseAccountUpdateUpdateStableV1Timing::Keep + }, + voting_for: if let Some(voting_for) = value.voting_for { + MinaBaseAccountUpdateUpdateStableV1VotingFor::Set(StateHash::from_str(&voting_for)?) + } else { + MinaBaseAccountUpdateUpdateStableV1VotingFor::Keep + }, + }) + } +} + +impl From for GraphQLFeePayer { + fn from(value: MinaBaseAccountUpdateFeePayerStableV1) -> Self { + Self { + authorization: value.authorization.to_string(), + body: GraphQLFeePayerBody { + public_key: value.body.public_key.to_string(), + fee: value.body.fee.as_u64().to_string(), + valid_until: value.body.valid_until.map(|v| v.as_u32().to_string()), + nonce: value.body.nonce.to_string(), + }, + } + } +} + +impl TryFrom for MinaBaseAccountUpdateFeePayerStableV1 { + type Error = ConversionError; + + fn try_from(value: InputGraphQLFeePayer) -> Result { + Ok(Self { + authorization: value.authorization.parse()?, + body: MinaBaseAccountUpdateBodyFeePayerStableV1 { + public_key: value.body.public_key.parse()?, + fee: CurrencyFeeStableV1(value.body.fee.parse::()?.into()), + valid_until: value + .body + .valid_until + .map(|v| -> Result<_, ConversionError> { + Ok(MinaNumbersGlobalSlotSinceGenesisMStableV1::SinceGenesis( + v.parse::()?.into(), + )) + }) + .transpose()?, + nonce: value.body.nonce.parse::()?.into(), + }, + }) + } +} + +impl TryFrom for GraphQLAccountUpdate { + type Error = ConversionError; + + fn try_from(value: MinaBaseAccountUpdateTStableV1) -> Result { + Ok(Self { + body: GraphQLAccountUpdateBody { + public_key: value.body.public_key.to_string(), + token_id: value.body.token_id.to_string(), + use_full_commitment: value.body.use_full_commitment, + increment_nonce: value.body.increment_nonce, + update: GraphQLAccountUpdateUpdate::try_from(value.body.update)?, + balance_change: GraphQLBalanceChange::from(value.body.balance_change), + events: value + .body + .events + .0 + .into_iter() + .map(|v| v.into_iter().map(|i| i.to_decimal()).collect()) + .collect(), + actions: value + .body + .actions + .0 + .into_iter() + .map(|v| v.into_iter().map(|i| i.to_decimal()).collect()) + .collect(), + call_data: value.body.call_data.to_decimal(), + // TODO(adonagy): figure out call depth + call_depth: 0, + preconditions: GraphQLPreconditions::from(value.body.preconditions), + may_use_token: GraphQLMayUseToken::from(value.body.may_use_token), + authorization_kind: GraphQLAuthorizationKind::from(value.body.authorization_kind), + implicit_account_creation_fee: value.body.implicit_account_creation_fee, + }, + authorization: GraphQLAuthorization::try_from(value.authorization)?, + }) + } +} + +impl TryFrom for MinaBaseAccountUpdateTStableV1 { + type Error = ConversionError; + + fn try_from(value: InputGraphQLAccountUpdate) -> Result { + Ok(Self { + body: MinaBaseAccountUpdateBodyStableV1 { + public_key: value.body.public_key.parse()?, + token_id: value.body.token_id.parse()?, + update: value.body.update.try_into()?, + balance_change: value.body.balance_change.try_into()?, + increment_nonce: value.body.increment_nonce, + events: MinaBaseAccountUpdateBodyEventsStableV1( + value + .body + .events + .into_iter() + .map(|v| { + v.into_iter() + .map(|i| BigInt::from_decimal(&i).map_err(ConversionError::from)) + .collect::>() + }) + .collect::>()?, + ), + actions: MinaBaseAccountUpdateBodyEventsStableV1( + value + .body + .actions + .into_iter() + .map(|v| { + v.into_iter() + .map(|i| BigInt::from_decimal(&i).map_err(ConversionError::from)) + .collect::>() + }) + .collect::>()?, + ), + call_data: BigInt::from_decimal(&value.body.call_data)?, + preconditions: value.body.preconditions.try_into()?, + use_full_commitment: value.body.use_full_commitment, + implicit_account_creation_fee: value.body.implicit_account_creation_fee, + may_use_token: value.body.may_use_token.into(), + authorization_kind: value.body.authorization_kind.try_into()?, + }, + authorization: value.authorization.try_into()?, + }) + } +} + +impl TryFrom for MinaBaseAccountUpdateUpdateTimingInfoStableV1 { + type Error = ConversionError; + + fn try_from(value: InputGraphQLTiming) -> Result { + let cliff_time: u32 = value.cliff_time.try_into()?; + let vesting_period: u32 = value.vesting_period.try_into()?; + Ok(Self { + initial_minimum_balance: CurrencyBalanceStableV1(CurrencyAmountStableV1( + value.initial_minimum_balance.parse::()?.into(), + )), + cliff_time: MinaNumbersGlobalSlotSinceGenesisMStableV1::SinceGenesis(cliff_time.into()), + cliff_amount: CurrencyAmountStableV1(value.cliff_amount.parse::()?.into()), + vesting_period: MinaNumbersGlobalSlotSpanStableV1::GlobalSlotSpan( + vesting_period.into(), + ), + vesting_increment: CurrencyAmountStableV1( + value.vesting_increment.parse::()?.into(), + ), + }) + } +} + +#[cfg(test)] +mod test { + use std::str::FromStr; + + use mina_p2p_messages::{ + binprot::BinProtRead, + v2::{ + MinaBaseSignedCommandMemoStableV1, MinaBaseUserCommandStableV2, + MinaBaseZkappCommandTStableV1WireStableV1, + }, + }; + + use super::*; + + #[test] + fn test_empty_memo() { + use ledger::scan_state::transaction_logic::Memo; + + let expected = "E4YM2vTHhWEg66xpj52JErHUBU4pZ1yageL4TVDDpTTSsv8mK6YaH"; + let empty_memo = Memo::from_str("").unwrap(); + let mina_empty_memo = MinaBaseSignedCommandMemoStableV1::from(&empty_memo); + assert_eq!(mina_empty_memo.to_base58check(), expected); + let empty_memo = Memo::empty(); + let mina_empty_memo = MinaBaseSignedCommandMemoStableV1::from(&empty_memo); + assert_eq!(mina_empty_memo.to_base58check(), expected); + } + + #[test] + fn test_zkapp_from_input() { + let bytes = include_bytes!("../../../../tests/files/zkapps/valid_zkapp.bin"); + let zkapp = + MinaBaseZkappCommandTStableV1WireStableV1::binprot_read(&mut bytes.as_slice()).unwrap(); + + let serialized_valid = serde_json::to_string_pretty(&zkapp).unwrap(); + + std::fs::write("zkapp_valid.json", &serialized_valid).unwrap(); + + let from_input = create_input_graphql_zkapp(); + let converted: MinaBaseUserCommandStableV2 = from_input.zkapp_command.try_into().unwrap(); + if let MinaBaseUserCommandStableV2::ZkappCommand(zkapp_cmd) = converted { + let serialized_converted = serde_json::to_string_pretty(&zkapp_cmd).unwrap(); + std::fs::write("zkapp_converted.json", &serialized_converted).unwrap(); + assert_eq!(serialized_valid, serialized_converted); + } else { + unreachable!() + } + } + + #[test] + fn test_authorization_kind() { + let kind = InputGraphQLAuthorizationKind { + is_signed: false, + is_proved: true, + verification_key_hash: Some( + "19951435866906059835892103359374709356309230417850637795098911039647240505427" + .to_string(), + ), + }; + let converted: Result = + kind.try_into(); + + assert!(converted.is_ok()); + } + + #[test] + fn test_authorization_proof() { + let proof = InputGraphQLAuthorization { + signature: None, + proof: Some( + include_str!("../../../../tests/files/zkapps/proof_string.txt").to_string(), + ), + }; + let converted: Result = proof.try_into(); + assert!(converted.is_ok()); + } + + fn create_input_graphql_zkapp() -> InputGraphQLZkapp { + InputGraphQLZkapp { + zkapp_command: InputGraphQLZkappCommand { + memo: Some("E4YM2vTHhWEg66xpj52JErHUBU4pZ1yageL4TVDDpTTSsv8mK6YaH".to_string()), + fee_payer: InputGraphQLFeePayer { + body: InputGraphQLFeePayerBody { + public_key: "B62qpD75xH5R19wxZG2uz8whNsHPTioVoYcPV3zfjjSbzTmaHQHKKEV".to_string(), + fee: "117000000".to_string(), + valid_until: None, + nonce: "1128".to_string(), + }, + authorization: "7mX5Lwu2bdnJPc4DJu7CkwTSR5behoKH8yZh7myCGgYfib5Sq3dfgPQY6LcXdrpQma1NvoLC5i7HLFEQZTnkBFcn96TP57JF".to_string(), + }, + account_updates: vec![ + InputGraphQLAccountUpdate { + body: InputGraphQLAccountUpdateBody { + call_depth: 0, + public_key: "B62qpD75xH5R19wxZG2uz8whNsHPTioVoYcPV3zfjjSbzTmaHQHKKEV".to_string(), + token_id: "wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf".to_string(), + update: InputGraphQLAccountUpdateUpdate { + app_state: vec![ + None, + None, + None, + None, + None, + None, + None, + None, + ], + delegate: None, + verification_key: None, + permissions: None, + zkapp_uri: None, + token_symbol: None, + timing: None, + voting_for: None, + }, + balance_change: InputGraphQLBalanceChange { + magnitude: "1000000000".to_string(), + sgn: "Negative".to_string(), + }, + increment_nonce: false, + events: vec![], + actions: vec![], + call_data: "0".to_string(), + preconditions: InputGraphQLPreconditions { + network: InputGraphQLPreconditionsNetwork { + snarked_ledger_hash: None, + blockchain_length: None, + min_window_density: None, + total_currency: None, + global_slot_since_genesis: None, + staking_epoch_data: InputGraphQLPreconditionsNetworkEpochData { + ledger: InputGraphQLPreconditionsNetworkLedger { + hash: None, + total_currency: None, + }, + seed: None, + start_checkpoint: None, + lock_checkpoint: None, + epoch_length: None, + }, + next_epoch_data: InputGraphQLPreconditionsNetworkEpochData { + ledger: InputGraphQLPreconditionsNetworkLedger { + hash: None, + total_currency: None, + }, + seed: None, + start_checkpoint: None, + lock_checkpoint: None, + epoch_length: None, + }, + }, + account: InputGraphQLPreconditionsAccount { + balance: None, + nonce: None, + receipt_chain_hash: None, + delegate: None, + state: vec![ + None, None, None, None, None, None, None, None + ], + action_state: None, + proved_state: None, + is_new: None, + }, + valid_while: None, + }, + use_full_commitment: true, + implicit_account_creation_fee: false, + may_use_token: InputGraphQLMayUseToken { + parents_own_token: false, + inherit_from_parent: false, + }, + authorization_kind: InputGraphQLAuthorizationKind { + is_signed: true, + is_proved: false, + verification_key_hash: None, + }, + }, + authorization: InputGraphQLAuthorization { + proof: None, + signature: Some("7mX5Lwu2bdnJPc4DJu7CkwTSR5behoKH8yZh7myCGgYfib5Sq3dfgPQY6LcXdrpQma1NvoLC5i7HLFEQZTnkBFcn96TP57JF".to_string()), + }, + }, + InputGraphQLAccountUpdate { + body: InputGraphQLAccountUpdateBody { + call_depth: 0, + public_key: "B62qqKAQh8M61uvuw3tjJsmRgsEvzRm84Nc9MwXTF3zoqFRZ86rV8qk".to_string(), + token_id: "wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf".to_string(), + update: InputGraphQLAccountUpdateUpdate { + app_state: vec![ + Some("1".to_string()), + Some("0".to_string()), + Some("0".to_string()), + Some("0".to_string()), + Some("0".to_string()), + Some("0".to_string()), + Some("0".to_string()), + Some("0".to_string()), + ], + delegate: None, + verification_key: Some(InputGraphQLVerificationKey { + data: "AACcenc1yLdGBm4xtUN1dpModROI0zovuy5rz2a94vfdBgG1C75BqviU4vw6JUYqODF8n9ivtfeU5s9PcpEGIP0htil2mfx8v2DB5RuNQ7VxJWkha0TSnJJsOl0FxhjldBbOY3tUZzZxHpPhHOKHz/ZAXRYFIsf2x+7boXC0iPurEX9VcnaJIq+YxxmnSfeYYxHkjxO9lrDBqjXzd5AHMnYyjTPC69B+5In7AOGS6R+A/g3/aR/MKDa4eDVrnsF9Oy/Ay8ahic2sSAZvtn08MdRyk/jm2cLlJbeAAad6Xyz/H9l7JrkbVwDMMPxvHVHs27tNoJCzIlrRzB7pg3ju9aQOu4h3thDr+WSgFQWKvcRPeL7f3TFjIr8WZ2457RgMcTwXwORKbqJCcyKVNOE+FlNwVkOKER+WIpC0OlgGuayPFwQQkbb91jaRlJvahfwkbF2+AJmDnavmNpop9T+/Xak1adXIrsRPeOjC+qIKxIbGimoMOoYzYlevKA80LnJ7HC0IxR+yNLvoSYxDDPNRD+OCCxk5lM2h8IDUiCNWH4FZNJ+doiigKjyZlu/xZ7jHcX7qibu/32KFTX85DPSkQM8dAEkH+vlkHmyXGLF4+xOVKeM0ihV5OEQrOABcgfTkbRsyxNInUBh0WiQyALE2ctjvkRCiE2P24bjFA8SgFmTM7gAKR89XcqLS/NP7lwCEej/L8q8R7sKGMCXmgFYluWH4JBSPDgvMxScfjFS33oBNb7po8cLnAORzohXoYTSgztklD0mKn6EegLbkLtwwr9ObsLz3m7fp/3wkNWFRkY5xzSZN1VybbQbmpyQNCpxd/kdDsvlszqlowkyC8HnKbhnvE0Mrz3ZIk4vSs/UGBSXAoESFCFCPcTq11TCOhE5rumMJErv5LusDHJgrBtQUMibLU9A1YbF7SPDAR2QZd0yx3waAC2F3xF+U682SOKF7oCZl2OICysRHqH+rZ604UfdGG0zWRuP2yg6kfGwcGQbO1ql40WrWTiFhbxxdKC7Gbz4y9Sb7q5EsPt6Z1AIn34/nXB/IWfC0gg/OgfPQTR7uxiTo2OOwjHni1f4KhT4rEmDAQn6ty6/ZRKHPWjUaAREbEw3tC36fI09hCYjjVTEmMAFTApk/tMUu0tC9Dt/vfDgXAlDJBwN5Y2Pt60qWY92skizVcWyWBxp5A8e4cVu3iToxOGUbSHzawovjubcH7qWjIZoghZJ16QB1c0ryiAfHB48OHhs2p/JZWz8Dp7kfcPkeg2Of2NbupJlNVMLIH4IGWaPAscBRkZ+F4oLqOhJ5as7fAzzU8PQdeZi0YgssGDJVmNEHP61I16KZNcxQqR0EUVwhyMmYmpVjvtfhHi/6I3TgYCmfnm6GL2sN144vMWg/gJ+p9a4GcEA0+gK3oCcKcwkq5rm+1Oxo9LWLp92Bdxq3iqfoIFmJ/ANGSbHF8StVmlVsP8zA+xuHylyiww/Lercce7cq0YA5PtYS3ge9IDYwXckBUXb5ikD3alrrv5mvMu6itB7ix2f8lbiF9Fkmc4Bk2ycIWXJDCuBN+2sTFqzUeoT6xY8XWaOcnDvqOgSm/CCSv38umiOE2jEpsKYxhRc6W70UJkrzd3hr2DiSF1I2B+krpUVK1GeOdCLC5sl7YPzk+pF8183uI9wse6UTlqIiroKqsggzLBy/IjAfxS0BxFy5zywXqp+NogFkoTEJmR5MaqOkPfap+OsD1lGScY6+X4WW/HqCWrmA3ZTqDGngQMTGXLCtl6IS/cQpihS1NRbNqOtKTaCB9COQu0oz6RivBlywuaj3MKUdmbQ2gVDj+SGQItCNaXawyPSBjB9VT+68SoJVySQsYPCuEZCb0V/40n/a7RAbyrnNjP+2HwD7p27Pl1RSzqq35xiPdnycD1UeEPLpx/ON65mYCkn+KLQZmkqPio+vA2KmJngWTx+ol4rVFimGm76VT0xCFDsu2K0YX0yoLNH4u2XfmT9NR8gGfkVRCnnNjlbgHQmEwC75+GmEJ5DjD3d+s6IXTQ60MHvxbTHHlnfmPbgKn2SAI0uVoewKC9GyK6dSaboLw3C48jl0E2kyc+7umhCk3kEeWmt//GSjRNhoq+B+mynXiOtgFs/Am2v1TBjSb+6tcijsf5tFJmeGxlCjJnTdNWBkSHpMoo6OFkkpA6/FBAUHLSM7Yv8oYyd0GtwF5cCwQ6aRTbl9oG/mUn5Q92OnDMQcUjpgEho0Dcp2OqZyyxqQSPrbIIZZQrS2HkxBgjcfcSTuSHo7ONqlRjLUpO5yS95VLGXBLLHuCiIMGT+DW6DoJRtRIS+JieVWBoX0YsWgYInXrVlWUv6gDng5AyVFkUIFwZk7/3mVAgvXO83ArVKA4S747jT60w5bgV4Jy55slDM=".to_string(), + hash: "11640126627177324946637007967436400725357874055180801746732941023691529117236".to_string(), + }), + permissions: Some(InputGraphQLAccountUpdateUpdatePermissions { + edit_state: "Proof".to_string(), + access: "Proof".to_string(), + send: "Proof".to_string(), + receive: "Proof".to_string(), + set_delegate: "Proof".to_string(), + set_permissions: "Proof".to_string(), + set_verification_key: InputGraphQLSetVerificationKeyPermissions { + auth: "Proof".to_string(), + txn_version: "3".to_string(), + }, + set_zkapp_uri: "Proof".to_string(), + edit_action_state: "Proof".to_string(), + set_token_symbol: "Proof".to_string(), + set_timing: "Proof".to_string(), + set_voting_for: "Proof".to_string(), + increment_nonce: "Proof".to_string(), + }), + zkapp_uri: None, + token_symbol: None, + timing: None, + voting_for: None, + }, + balance_change: InputGraphQLBalanceChange { + magnitude: "0".to_string(), + sgn: "Positive".to_string(), + }, + increment_nonce: true, + events: vec![], + actions: vec![], + call_data: "0".to_string(), + preconditions: InputGraphQLPreconditions { + network: InputGraphQLPreconditionsNetwork { + snarked_ledger_hash: None, + blockchain_length: None, + min_window_density: None, + total_currency: None, + global_slot_since_genesis: None, + staking_epoch_data: InputGraphQLPreconditionsNetworkEpochData { + ledger: InputGraphQLPreconditionsNetworkLedger { + hash: None, + total_currency: None, + }, + seed: None, + start_checkpoint: None, + lock_checkpoint: None, + epoch_length: None, + }, + next_epoch_data: InputGraphQLPreconditionsNetworkEpochData { + ledger: InputGraphQLPreconditionsNetworkLedger { + hash: None, + total_currency: None, + }, + seed: None, + start_checkpoint: None, + lock_checkpoint: None, + epoch_length: None, + }, + }, + account: InputGraphQLPreconditionsAccount { + balance: None, + nonce: Some(InputGraphQLPreconditionsNetworkBounds { + upper: "0".to_string(), + lower: "0".to_string(), + }), + receipt_chain_hash: None, + delegate: None, + state: vec![ + None, None, None, None, None, None, None, None + ], + action_state: None, + proved_state: Some(false), + is_new: None, + }, + valid_while: None, + }, + use_full_commitment: false, + implicit_account_creation_fee: false, + may_use_token: InputGraphQLMayUseToken { + parents_own_token: false, + inherit_from_parent: false, + }, + authorization_kind: InputGraphQLAuthorizationKind { + is_signed: true, + is_proved: false, + verification_key_hash: None, + }, + }, + authorization: InputGraphQLAuthorization { + proof: None, + signature: Some("7mXFnDxZBE5iXBfw9LRPXST3sSodXAdTJSWFqX3hBoDA3wv5s2s9TLMDCXgatMvMH4bDttAFyJuezWmbSA81FXeMFZgqcxtt".to_string()), + }, + }, + ], + }, + } + } + + #[test] + pub fn test_bigint_to_decimal() { + let bigint = BigInt::from_decimal("1").unwrap(); + let decimal = serde_json::to_string(&bigint).unwrap(); + assert_eq!( + decimal, + "\"0x0000000000000000000000000000000000000000000000000000000000000001\"".to_string() + ); + } +} diff --git a/node/native/src/http_server.rs b/node/native/src/http_server.rs index 458b932a27..e195a169ba 100644 --- a/node/native/src/http_server.rs +++ b/node/native/src/http_server.rs @@ -453,14 +453,12 @@ pub async fn run(port: u16, rpc_sender: RpcSender) { let rpc_sender_clone = rpc_sender_clone.clone(); async move { rpc_sender_clone - .oneshot_request(RpcRequest::TransactionPoolGet) + .transaction_pool() + .get() .await - .map_or_else( - dropped_channel_response, - |reply: node::rpc::RpcTransactionPoolResponse| { - with_json_reply(&reply, StatusCode::OK) - }, - ) + .map_or_else(dropped_channel_response, |reply| { + with_json_reply(&reply, StatusCode::OK) + }) } }); @@ -470,11 +468,14 @@ pub async fn run(port: u16, rpc_sender: RpcSender) { async move { rpc_sender_clone - .oneshot_request(RpcRequest::LedgerAccountsGet(None)) + .ledger() + .latest() + .accounts() + .all() .await .map_or_else( dropped_channel_response, - |reply: node::rpc::RpcLedgerAccountsResponse| { + |reply: node::rpc::RpcLedgerSlimAccountsResponse| { with_json_reply(&reply, StatusCode::OK) }, ) @@ -485,20 +486,27 @@ pub async fn run(port: u16, rpc_sender: RpcSender) { let transaction_post = warp::path("send-payment") .and(warp::post()) .and(warp::filters::body::json()) - .then(move |body: Vec<_>| { + .then(move |body: Vec| { let rpc_sender_clone = rpc_sender_clone.clone(); async move { - println!("Transaction inject post: {:#?}", body); - rpc_sender_clone - .oneshot_request(RpcRequest::TransactionInject(body)) + match rpc_sender_clone + .transaction_pool() + .inject() + .payment(body) .await - .map_or_else( + { + Err(err) => with_status( + warp::reply::json(&serde_json::json!({"error": err})), + StatusCode::INTERNAL_SERVER_ERROR, + ), + Ok(res) => res.map_or_else( dropped_channel_response, |reply: node::rpc::RpcTransactionInjectResponse| { with_json_reply(&reply, StatusCode::OK) }, - ) + ), + } } }); @@ -510,14 +518,13 @@ pub async fn run(port: u16, rpc_sender: RpcSender) { async move { rpc_sender_clone - .oneshot_request(RpcRequest::TransitionFrontierUserCommandsGet) + .transition_frontier() + .best_chain() + .user_commands() .await - .map_or_else( - dropped_channel_response, - |reply: node::rpc::RpcTransitionFrontierUserCommandsResponse| { - with_json_reply(&reply, StatusCode::OK) - }, - ) + .map_or_else(dropped_channel_response, |reply| { + with_json_reply(&reply, StatusCode::OK) + }) } }); diff --git a/node/native/src/node/builder.rs b/node/native/src/node/builder.rs index 688183c776..2607a17334 100644 --- a/node/native/src/node/builder.rs +++ b/node/native/src/node/builder.rs @@ -284,12 +284,16 @@ impl NodeBuilder { .unwrap_or_else(redux::Timestamp::global_now); let protocol_constants = self.genesis_config.protocol_constants()?; + let consensus_consts = + ConsensusConstants::create(constraint_constants(), &protocol_constants); // build config let node_config = node::Config { global: GlobalConfig { build: node::BuildEnv::get().into(), snarker: self.snarker, + consensus_constants: consensus_consts.clone(), + testing_run: false, }, p2p: P2pConfig { libp2p_port: self.p2p_libp2p_port, @@ -332,9 +336,6 @@ impl NodeBuilder { service.p2p_init(p2p_sec_key); } - let consensus_consts = - ConsensusConstants::create(constraint_constants(), &protocol_constants); - let service = service.build()?; let state = node::State::new(node_config, &consensus_consts, initial_time); diff --git a/node/src/action.rs b/node/src/action.rs index c41c51168f..0669809e9e 100644 --- a/node/src/action.rs +++ b/node/src/action.rs @@ -8,6 +8,7 @@ pub use crate::consensus::ConsensusAction; pub use crate::event_source::EventSourceAction; pub use crate::external_snark_worker::ExternalSnarkWorkerAction; pub use crate::ledger::LedgerAction; +use crate::p2p::callbacks::P2pCallbacksAction; pub use crate::p2p::P2pAction; pub use crate::rpc::RpcAction; pub use crate::snark::SnarkAction; @@ -32,6 +33,8 @@ pub enum Action { EventSource(EventSourceAction), P2p(P2pAction), + P2pCallbacks(P2pCallbacksAction), + Ledger(LedgerAction), Snark(SnarkAction), Consensus(ConsensusAction), @@ -85,6 +88,7 @@ impl redux::EnablingCondition for Action { Action::WatchedAccounts(a) => a.is_enabled(state, time), Action::TransactionPool(a) => a.is_enabled(state, time), Action::TransactionPoolEffect(a) => a.is_enabled(state, time), + Action::P2pCallbacks(a) => a.is_enabled(state, time), } } } diff --git a/node/src/action_kind.rs b/node/src/action_kind.rs index 7eaee37c84..ff2b74ec88 100644 --- a/node/src/action_kind.rs +++ b/node/src/action_kind.rs @@ -23,6 +23,7 @@ use crate::external_snark_worker::ExternalSnarkWorkerAction; use crate::ledger::read::LedgerReadAction; use crate::ledger::write::LedgerWriteAction; use crate::ledger::LedgerAction; +use crate::p2p::callbacks::P2pCallbacksAction; use crate::p2p::channels::best_tip::P2pChannelsBestTipAction; use crate::p2p::channels::best_tip_effectful::P2pChannelsBestTipEffectfulAction; use crate::p2p::channels::rpc::P2pChannelsRpcAction; @@ -147,6 +148,7 @@ pub enum ActionKind { ConsensusBlockSnarkVerifySuccess, ConsensusDetectForkRange, ConsensusLongRangeForkResolve, + ConsensusP2pBestTipUpdate, ConsensusPrune, ConsensusShortRangeForkResolve, EventSourceNewEvent, @@ -174,6 +176,15 @@ pub enum ActionKind { LedgerWriteInit, LedgerWritePending, LedgerWriteSuccess, + P2pCallbacksP2pChannelsRpcReady, + P2pCallbacksP2pChannelsRpcRequestReceived, + P2pCallbacksP2pChannelsRpcResponseReceived, + P2pCallbacksP2pChannelsRpcTimeout, + P2pCallbacksP2pChannelsStreamingRpcReady, + P2pCallbacksP2pChannelsStreamingRpcResponseReceived, + P2pCallbacksP2pChannelsStreamingRpcTimeout, + P2pCallbacksP2pDisconnection, + P2pCallbacksRpcRespondBestTip, P2pChannelsBestTipInit, P2pChannelsBestTipPending, P2pChannelsBestTipReady, @@ -415,7 +426,9 @@ pub enum ActionKind { P2pPeerReady, P2pPeerRemove, RpcActionStatsGet, + RpcBestChain, RpcBlockProducerStatsGet, + RpcConsensusConstantsGet, RpcDiscoveryBoostrapStats, RpcDiscoveryRoutingTable, RpcFinish, @@ -425,6 +438,7 @@ pub enum ActionKind { RpcLedgerAccountsGetPending, RpcLedgerAccountsGetSuccess, RpcMessageProgressGet, + RpcP2pConnectionIncomingAnswerReady, RpcP2pConnectionIncomingError, RpcP2pConnectionIncomingInit, RpcP2pConnectionIncomingPending, @@ -454,6 +468,7 @@ pub enum ActionKind { RpcTransactionInjectRejected, RpcTransactionInjectSuccess, RpcTransactionPool, + RpcTransactionStatusGet, RpcTransitionFrontierUserCommandsGet, SnarkBlockVerifyError, SnarkBlockVerifyFinish, @@ -596,7 +611,7 @@ pub enum ActionKind { } impl ActionKind { - pub const COUNT: u16 = 490; + pub const COUNT: u16 = 504; } impl std::fmt::Display for ActionKind { @@ -611,6 +626,7 @@ impl ActionKindGet for Action { Self::CheckTimeouts(a) => a.kind(), Self::EventSource(a) => a.kind(), Self::P2p(a) => a.kind(), + Self::P2pCallbacks(a) => a.kind(), Self::Ledger(a) => a.kind(), Self::Snark(a) => a.kind(), Self::Consensus(a) => a.kind(), @@ -661,6 +677,32 @@ impl ActionKindGet for P2pAction { } } +impl ActionKindGet for P2pCallbacksAction { + fn kind(&self) -> ActionKind { + match self { + Self::P2pChannelsRpcReady { .. } => ActionKind::P2pCallbacksP2pChannelsRpcReady, + Self::P2pChannelsRpcTimeout { .. } => ActionKind::P2pCallbacksP2pChannelsRpcTimeout, + Self::P2pChannelsRpcResponseReceived { .. } => { + ActionKind::P2pCallbacksP2pChannelsRpcResponseReceived + } + Self::P2pChannelsRpcRequestReceived { .. } => { + ActionKind::P2pCallbacksP2pChannelsRpcRequestReceived + } + Self::P2pChannelsStreamingRpcReady => { + ActionKind::P2pCallbacksP2pChannelsStreamingRpcReady + } + Self::P2pChannelsStreamingRpcTimeout { .. } => { + ActionKind::P2pCallbacksP2pChannelsStreamingRpcTimeout + } + Self::P2pChannelsStreamingRpcResponseReceived { .. } => { + ActionKind::P2pCallbacksP2pChannelsStreamingRpcResponseReceived + } + Self::P2pDisconnection { .. } => ActionKind::P2pCallbacksP2pDisconnection, + Self::RpcRespondBestTip { .. } => ActionKind::P2pCallbacksRpcRespondBestTip, + } + } +} + impl ActionKindGet for LedgerAction { fn kind(&self) -> ActionKind { match self { @@ -695,6 +737,7 @@ impl ActionKindGet for ConsensusAction { Self::ShortRangeForkResolve { .. } => ActionKind::ConsensusShortRangeForkResolve, Self::LongRangeForkResolve { .. } => ActionKind::ConsensusLongRangeForkResolve, Self::BestTipUpdate { .. } => ActionKind::ConsensusBestTipUpdate, + Self::P2pBestTipUpdate { .. } => ActionKind::ConsensusP2pBestTipUpdate, Self::Prune => ActionKind::ConsensusPrune, } } @@ -854,6 +897,9 @@ impl ActionKindGet for RpcAction { Self::P2pConnectionIncomingRespond { .. } => { ActionKind::RpcP2pConnectionIncomingRespond } + Self::P2pConnectionIncomingAnswerReady { .. } => { + ActionKind::RpcP2pConnectionIncomingAnswerReady + } Self::P2pConnectionIncomingError { .. } => ActionKind::RpcP2pConnectionIncomingError, Self::P2pConnectionIncomingSuccess { .. } => { ActionKind::RpcP2pConnectionIncomingSuccess @@ -886,6 +932,9 @@ impl ActionKindGet for RpcAction { Self::TransitionFrontierUserCommandsGet { .. } => { ActionKind::RpcTransitionFrontierUserCommandsGet } + Self::BestChain { .. } => ActionKind::RpcBestChain, + Self::ConsensusConstantsGet { .. } => ActionKind::RpcConsensusConstantsGet, + Self::TransactionStatusGet { .. } => ActionKind::RpcTransactionStatusGet, Self::Finish { .. } => ActionKind::RpcFinish, } } diff --git a/node/src/block_producer/block_producer_effects.rs b/node/src/block_producer/block_producer_effects.rs index a48d27106b..66bca390a4 100644 --- a/node/src/block_producer/block_producer_effects.rs +++ b/node/src/block_producer/block_producer_effects.rs @@ -3,6 +3,7 @@ use mina_p2p_messages::v2::{ MinaStateSnarkTransitionValueStableV2, ProverExtendBlockchainInputStableV2, }; use openmina_core::bug_condition; +use openmina_core::consensus::in_seed_update_range; use crate::account::AccountSecretKey; use crate::ledger::write::{LedgerWriteAction, LedgerWriteRequest}; @@ -56,6 +57,7 @@ pub fn block_producer_effects( }; let next_epoch_first_slot = next_epoch_first_slot(&global_slot); let current_epoch = store.state().current_epoch(); + let current_slot = store.state().current_slot(); store.dispatch(BlockProducerVrfEvaluatorAction::InitializeEvaluator { best_tip: best_tip.clone(), @@ -77,8 +79,15 @@ pub fn block_producer_effects( } } + let is_next_epoch_seed_finalized = if let Some(current_slot) = current_slot { + !in_seed_update_range(current_slot, best_tip.constants()) + } else { + false + }; + store.dispatch(BlockProducerVrfEvaluatorAction::CheckEpochEvaluability { current_epoch, + is_next_epoch_seed_finalized, root_block_epoch, best_tip_epoch, best_tip_slot, diff --git a/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_actions.rs b/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_actions.rs index 6d2f337b1a..9a1afb2c6d 100644 --- a/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_actions.rs +++ b/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_actions.rs @@ -46,6 +46,7 @@ pub enum BlockProducerVrfEvaluatorAction { #[action_event(level = info, fields(current_epoch, best_tip_epoch, best_tip_slot, best_tip_global_slot))] CheckEpochEvaluability { current_epoch: Option, + is_next_epoch_seed_finalized: bool, best_tip_epoch: u32, root_block_epoch: u32, best_tip_slot: u32, diff --git a/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_effects.rs b/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_effects.rs index 181fafe410..f174780c41 100644 --- a/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_effects.rs +++ b/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_effects.rs @@ -110,6 +110,7 @@ impl BlockProducerVrfEvaluatorAction { best_tip_slot, next_epoch_first_slot, current_epoch: _, + is_next_epoch_seed_finalized: _, staking_epoch_data: _, next_epoch_data: _, } => { diff --git a/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_reducer.rs b/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_reducer.rs index 7a36d7948f..37b53fb660 100644 --- a/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_reducer.rs +++ b/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_reducer.rs @@ -65,6 +65,7 @@ impl BlockProducerVrfEvaluatorState { } BlockProducerVrfEvaluatorAction::CheckEpochEvaluability { current_epoch, + is_next_epoch_seed_finalized, best_tip_epoch, root_block_epoch, staking_epoch_data, @@ -76,6 +77,7 @@ impl BlockProducerVrfEvaluatorState { self.status = BlockProducerVrfEvaluatorStatus::ReadinessCheck { time: meta.time(), current_epoch: *current_epoch, + is_next_epoch_seed_finalized: *is_next_epoch_seed_finalized, best_tip_epoch: *best_tip_epoch, root_block_epoch: *root_block_epoch, is_current_epoch_evaluated: self.is_epoch_evaluated(*best_tip_epoch), diff --git a/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_state.rs b/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_state.rs index fefb7fc24a..78c0b34b32 100644 --- a/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_state.rs +++ b/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_state.rs @@ -91,6 +91,7 @@ impl BlockProducerVrfEvaluatorState { best_tip_epoch, root_block_epoch, current_epoch, + is_next_epoch_seed_finalized, staking_epoch_data, next_epoch_data, .. @@ -111,7 +112,7 @@ impl BlockProducerVrfEvaluatorState { if !self.is_epoch_evaluated(best_tip_epoch) { self.epoch_context = EpochContext::Current((*staking_epoch_data).into()) } else if !self.is_epoch_evaluated(best_tip_epoch + 1) { - if root_block_epoch == best_tip_epoch { + if root_block_epoch == best_tip_epoch && is_next_epoch_seed_finalized { self.epoch_context = EpochContext::Next((*next_epoch_data).into()) } else { self.epoch_context = EpochContext::Waiting @@ -495,6 +496,7 @@ pub enum BlockProducerVrfEvaluatorStatus { ReadinessCheck { time: redux::Timestamp, current_epoch: Option, + is_next_epoch_seed_finalized: bool, best_tip_epoch: u32, root_block_epoch: u32, is_current_epoch_evaluated: bool, @@ -658,6 +660,7 @@ mod test { best_tip_epoch: 0, is_current_epoch_evaluated: false, is_next_epoch_evaluated: false, + is_next_epoch_seed_finalized: false, last_evaluated_epoch: None, staking_epoch_data: Box::new(DUMMY_STAKING_EPOCH_DATA.to_owned()), next_epoch_data: Box::new(DUMMY_NEXT_EPOCH_DATA.to_owned()), @@ -680,6 +683,7 @@ mod test { best_tip_epoch: 0, is_current_epoch_evaluated: true, is_next_epoch_evaluated: false, + is_next_epoch_seed_finalized: true, last_evaluated_epoch: Some(0), staking_epoch_data: Box::new(DUMMY_STAKING_EPOCH_DATA.to_owned()), next_epoch_data: Box::new(DUMMY_NEXT_EPOCH_DATA.to_owned()), @@ -702,6 +706,7 @@ mod test { best_tip_epoch: 0, is_current_epoch_evaluated: true, is_next_epoch_evaluated: true, + is_next_epoch_seed_finalized: true, last_evaluated_epoch: Some(1), staking_epoch_data: Box::new(DUMMY_STAKING_EPOCH_DATA.to_owned()), next_epoch_data: Box::new(DUMMY_NEXT_EPOCH_DATA.to_owned()), @@ -724,6 +729,7 @@ mod test { best_tip_epoch: 2, is_current_epoch_evaluated: false, is_next_epoch_evaluated: false, + is_next_epoch_seed_finalized: false, last_evaluated_epoch: None, staking_epoch_data: Box::new(DUMMY_STAKING_EPOCH_DATA.to_owned()), next_epoch_data: Box::new(DUMMY_NEXT_EPOCH_DATA.to_owned()), @@ -747,6 +753,7 @@ mod test { is_current_epoch_evaluated: true, is_next_epoch_evaluated: false, last_evaluated_epoch: Some(2), + is_next_epoch_seed_finalized: false, staking_epoch_data: Box::new(DUMMY_STAKING_EPOCH_DATA.to_owned()), next_epoch_data: Box::new(DUMMY_NEXT_EPOCH_DATA.to_owned()), }, @@ -804,6 +811,7 @@ mod test { #[test] fn generic_epoch_correctly_switch_to_next_epoch() { // Staking ledger not yet materialized (wait k=290 blocks) + // The epoch seed is not finalized yet let mut vrf_evaluator_state = SECOND_EPOCH_CURRENT_EPOCH_EVALUATED_WAIT_FOR_NEXT .lock() .unwrap(); @@ -815,6 +823,7 @@ mod test { // Epoch has changed but the root is still from the previous epoch. // Next epoch must not be evaluated yet. + // The epoch seed is not finalized yet. vrf_evaluator_state.status = BlockProducerVrfEvaluatorStatus::ReadinessCheck { time: redux::Timestamp::global_now(), current_epoch: Some(2), // TODO(adonagy) @@ -822,6 +831,7 @@ mod test { best_tip_epoch: 2, is_current_epoch_evaluated: true, is_next_epoch_evaluated: false, + is_next_epoch_seed_finalized: false, last_evaluated_epoch: Some(2), staking_epoch_data: Box::new(DUMMY_STAKING_EPOCH_DATA.to_owned()), next_epoch_data: Box::new(DUMMY_NEXT_EPOCH_DATA.to_owned()), @@ -834,7 +844,7 @@ mod test { )); // Epoch has changed, and the root is already at that epoch too. - // Next epoch must be evaluated now. + // The epoch seed is still not finalized. vrf_evaluator_state.status = BlockProducerVrfEvaluatorStatus::ReadinessCheck { time: redux::Timestamp::global_now(), current_epoch: Some(2), // TODO(adonagy) @@ -842,6 +852,28 @@ mod test { best_tip_epoch: 2, is_current_epoch_evaluated: true, is_next_epoch_evaluated: false, + is_next_epoch_seed_finalized: false, + last_evaluated_epoch: Some(2), + staking_epoch_data: Box::new(DUMMY_STAKING_EPOCH_DATA.to_owned()), + next_epoch_data: Box::new(DUMMY_NEXT_EPOCH_DATA.to_owned()), + }; + + vrf_evaluator_state.set_epoch_context(); + assert!(matches!( + vrf_evaluator_state.epoch_context(), + EpochContext::Waiting + )); + + // Epoch has changed, and the root is already at that epoch too. + // The epoch seed is also finalized. + vrf_evaluator_state.status = BlockProducerVrfEvaluatorStatus::ReadinessCheck { + time: redux::Timestamp::global_now(), + current_epoch: Some(2), // TODO(adonagy) + root_block_epoch: 2, + best_tip_epoch: 2, + is_current_epoch_evaluated: true, + is_next_epoch_evaluated: false, + is_next_epoch_seed_finalized: true, last_evaluated_epoch: Some(2), staking_epoch_data: Box::new(DUMMY_STAKING_EPOCH_DATA.to_owned()), next_epoch_data: Box::new(DUMMY_NEXT_EPOCH_DATA.to_owned()), diff --git a/node/src/config.rs b/node/src/config.rs index c53feb8592..991ccfd882 100644 --- a/node/src/config.rs +++ b/node/src/config.rs @@ -2,6 +2,7 @@ use std::str::FromStr; use std::sync::Arc; use mina_p2p_messages::v2::CurrencyFeeStableV1; +use openmina_core::consensus::ConsensusConstants; use serde::{Deserialize, Serialize}; use crate::account::AccountPublicKey; @@ -31,6 +32,8 @@ pub struct Config { pub struct GlobalConfig { pub build: Box, pub snarker: Option, + pub consensus_constants: ConsensusConstants, + pub testing_run: bool, } #[derive(Serialize, Deserialize, Debug, Clone)] diff --git a/node/src/consensus/consensus_actions.rs b/node/src/consensus/consensus_actions.rs index f9b80d7d7f..48a8ea2c50 100644 --- a/node/src/consensus/consensus_actions.rs +++ b/node/src/consensus/consensus_actions.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use mina_p2p_messages::v2::{MinaBlockBlockStableV2, StateHash}; -use openmina_core::block::ArcBlockWithHash; +use openmina_core::block::{ArcBlockWithHash, BlockWithHash}; use openmina_core::{action_event, ActionEvent}; use serde::{Deserialize, Serialize}; use snark::block_verify::SnarkBlockVerifyError; @@ -53,6 +53,9 @@ pub enum ConsensusAction { BestTipUpdate { hash: StateHash, }, + P2pBestTipUpdate { + best_tip: BlockWithHash>, + }, Prune, } @@ -146,6 +149,7 @@ impl redux::EnablingCondition for ConsensusAction { .consensus .is_candidate_decided_to_use_as_tip(hash) }, + ConsensusAction::P2pBestTipUpdate { .. } => true, ConsensusAction::Prune => { state.consensus.best_tip().is_some() }, diff --git a/node/src/consensus/consensus_reducer.rs b/node/src/consensus/consensus_reducer.rs index 0c6e6c99fe..22da88cd60 100644 --- a/node/src/consensus/consensus_reducer.rs +++ b/node/src/consensus/consensus_reducer.rs @@ -5,7 +5,14 @@ use openmina_core::{ use snark::block_verify::{SnarkBlockVerifyAction, SnarkBlockVerifyError}; use crate::{ - transition_frontier::sync::TransitionFrontierSyncAction, Action, State, WatchedAccountsAction, + transition_frontier::sync::{ + ledger::{ + snarked::TransitionFrontierSyncLedgerSnarkedAction, + staged::TransitionFrontierSyncLedgerStagedAction, + }, + TransitionFrontierSyncAction, + }, + Action, State, WatchedAccountsAction, }; use super::{ @@ -235,6 +242,18 @@ impl ConsensusState { transition_frontier_new_best_tip_handler(global_state, dispatcher); } + ConsensusAction::P2pBestTipUpdate { best_tip } => { + let dispatcher = state_context.into_dispatcher(); + dispatcher.push(ConsensusAction::BlockReceived { + hash: best_tip.hash.clone(), + block: best_tip.block.clone(), + chain_proof: None, + }); + + dispatcher.push(TransitionFrontierSyncLedgerSnarkedAction::PeersQuery); + dispatcher.push(TransitionFrontierSyncLedgerStagedAction::PartsPeerFetchInit); + dispatcher.push(TransitionFrontierSyncAction::BlocksPeersQuery); + } ConsensusAction::Prune => { let Some(best_tip_hash) = state.best_tip.clone() else { return; diff --git a/node/src/effects.rs b/node/src/effects.rs index 6b0b3b4fa0..bc6aa6a205 100644 --- a/node/src/effects.rs +++ b/node/src/effects.rs @@ -1,5 +1,4 @@ use openmina_core::log::system_time; -use p2p::p2p_timeout_effects; use crate::block_producer::{block_producer_effects, BlockProducerAction}; use crate::event_source::event_source_effects; @@ -37,8 +36,6 @@ pub fn effects(store: &mut Store, action: ActionWithMeta) { store.dispatch(ExternalSnarkWorkerAction::Start); if store.state().p2p.ready().is_some() { - p2p_timeout_effects(store, &meta); - p2p_request_best_tip_if_needed(store); p2p_request_transactions_if_needed(store); p2p_request_snarks_if_needed(store); @@ -95,6 +92,9 @@ pub fn effects(store: &mut Store, action: ActionWithMeta) { Action::WatchedAccounts(_) => { // Handled by reducer } + Action::P2pCallbacks(_) => { + // Handled by reducer + } } } diff --git a/node/src/event_source/event.rs b/node/src/event_source/event.rs index 853c6ceae3..c37a913b6e 100644 --- a/node/src/event_source/event.rs +++ b/node/src/event_source/event.rs @@ -61,13 +61,16 @@ impl std::fmt::Display for Event { RpcRequest::DiscoveryRoutingTable => write!(f, "DiscoveryRoutingTable"), RpcRequest::DiscoveryBoostrapStats => write!(f, "DiscoveryBoostrapStats"), RpcRequest::TransactionPoolGet => write!(f, "TransactionPool"), - RpcRequest::LedgerAccountsGet(pub_key) => { - write!(f, "LedgerAccountsGet, {pub_key:?}") + RpcRequest::LedgerAccountsGet(account_query) => { + write!(f, "LedgerAccountsGet, {account_query:?}") } RpcRequest::TransactionInject(..) => write!(f, "TransactionInject"), RpcRequest::TransitionFrontierUserCommandsGet => { write!(f, "TransitionFrontierUserCommandsGet") } + RpcRequest::BestChain(..) => write!(f, "BestChain"), + RpcRequest::ConsensusConstantsGet => write!(f, "ConsensusConstantsGet"), + RpcRequest::TransactionStatusGet(..) => write!(f, "TransactionStatusGet"), } } Self::ExternalSnarkWorker(event) => { diff --git a/node/src/event_source/event_source_effects.rs b/node/src/event_source/event_source_effects.rs index 570a924c8b..b7f129c627 100644 --- a/node/src/event_source/event_source_effects.rs +++ b/node/src/event_source/event_source_effects.rs @@ -345,8 +345,11 @@ pub fn event_source_effects(store: &mut Store, action: EventSourc RpcRequest::TransactionPoolGet => { store.dispatch(RpcAction::TransactionPool { rpc_id }); } - RpcRequest::LedgerAccountsGet(public_key) => { - store.dispatch(RpcAction::LedgerAccountsGetInit { rpc_id, public_key }); + RpcRequest::LedgerAccountsGet(account_query) => { + store.dispatch(RpcAction::LedgerAccountsGetInit { + rpc_id, + account_query, + }); } RpcRequest::TransactionInject(commands) => { store.dispatch(RpcAction::TransactionInjectInit { rpc_id, commands }); @@ -354,6 +357,15 @@ pub fn event_source_effects(store: &mut Store, action: EventSourc RpcRequest::TransitionFrontierUserCommandsGet => { store.dispatch(RpcAction::TransitionFrontierUserCommandsGet { rpc_id }); } + RpcRequest::BestChain(max_length) => { + store.dispatch(RpcAction::BestChain { rpc_id, max_length }); + } + RpcRequest::ConsensusConstantsGet => { + store.dispatch(RpcAction::ConsensusConstantsGet { rpc_id }); + } + RpcRequest::TransactionStatusGet(tx) => { + store.dispatch(RpcAction::TransactionStatusGet { rpc_id, tx }); + } }, Event::ExternalSnarkWorker(e) => match e { ExternalSnarkWorkerEvent::Started => { diff --git a/node/src/ledger/ledger_effects.rs b/node/src/ledger/ledger_effects.rs index 137657faf6..90bc9fa136 100644 --- a/node/src/ledger/ledger_effects.rs +++ b/node/src/ledger/ledger_effects.rs @@ -258,7 +258,7 @@ fn next_read_requests_init(store: &mut Store) { for (rpc_id, req) in ledger_account_rpc { store.dispatch(RpcAction::LedgerAccountsGetInit { rpc_id, - public_key: req, + account_query: req, }); if !store.state().ledger.read.is_total_cost_under_limit() { return; @@ -487,9 +487,13 @@ fn propagate_read_response( } } (_, LedgerReadResponse::ScanStateSummary(..)) => unreachable!(), - (_req, LedgerReadResponse::GetAccounts(_)) => todo!(), - (_, LedgerReadResponse::AccountsForRpc(rpc_id, accounts)) => { - store.dispatch(RpcAction::LedgerAccountsGetSuccess { rpc_id, accounts }); + (_req, LedgerReadResponse::GetAccounts(..)) => todo!(), + (_, LedgerReadResponse::AccountsForRpc(rpc_id, accounts, account_query)) => { + store.dispatch(RpcAction::LedgerAccountsGetSuccess { + rpc_id, + accounts, + account_query, + }); } } } diff --git a/node/src/ledger/ledger_manager.rs b/node/src/ledger/ledger_manager.rs index 9c515f3fc1..064cf6d5e3 100644 --- a/node/src/ledger/ledger_manager.rs +++ b/node/src/ledger/ledger_manager.rs @@ -1,6 +1,6 @@ use std::collections::BTreeMap; -use ledger::staged_ledger::staged_ledger::StagedLedger; +use ledger::staged_ledger::staged_ledger::{SkipVerification, StagedLedger}; use mina_p2p_messages::v2::{self, LedgerHash, MinaBaseAccountBinableArgStableV2}; use openmina_core::channels::mpsc; use openmina_core::thread; @@ -11,6 +11,7 @@ use super::write::{LedgerWriteRequest, LedgerWriteResponse}; use super::LedgerService; use crate::account::AccountPublicKey; use crate::ledger::LedgerAddress; +use crate::rpc::AccountQuery; use crate::transition_frontier::sync::ledger::snarked::TransitionFrontierSyncLedgerSnarkedService; use ledger::{Account, AccountId, Mask}; use mina_signer::CompressedPubKey; @@ -153,9 +154,18 @@ impl LedgerRequest { result: result.map(Into::into), } } - LedgerWriteRequest::BlockApply { block, pred_block } => { + LedgerWriteRequest::BlockApply { + block, + pred_block, + skip_verification, + } => { let block_hash = block.hash().clone(); - let result = ledger_ctx.block_apply(block, pred_block); + let skip_verification = if skip_verification { + Some(SkipVerification::All) + } else { + None + }; + let result = ledger_ctx.block_apply(block, pred_block, skip_verification); LedgerWriteResponse::BlockApply { block_hash, result } } LedgerWriteRequest::Commit { @@ -220,13 +230,25 @@ impl LedgerRequest { let res = ledger_ctx.scan_state_summary(&ledger_hash); LedgerReadResponse::ScanStateSummary(res) } - LedgerReadRequest::GetAccounts(ledger_hash, account_ids) => { + LedgerReadRequest::GetAccounts(ledger_hash, account_ids, rpc_id) => { let res = ledger_ctx.get_accounts(ledger_hash, account_ids); - LedgerReadResponse::GetAccounts(res) + LedgerReadResponse::GetAccounts(res, rpc_id) } - LedgerReadRequest::AccountsForRpc(rpc_id, ledger_hash, public_key) => { - let res = ledger_ctx.get_accounts_for_rpc(ledger_hash, public_key); - LedgerReadResponse::AccountsForRpc(rpc_id, res) + LedgerReadRequest::AccountsForRpc(rpc_id, ledger_hash, account_query) => { + let res = match &account_query { + AccountQuery::SinglePublicKey(public_key) => ledger_ctx + .get_accounts_for_rpc(ledger_hash, Some(public_key.clone())), + AccountQuery::All => ledger_ctx.get_accounts_for_rpc(ledger_hash, None), + AccountQuery::PubKeyWithTokenId(public_key, token_id_key_hash) => { + let id = AccountId { + public_key: public_key.clone().try_into().unwrap(), + token_id: token_id_key_hash.clone().into(), + }; + ledger_ctx.get_accounts(ledger_hash, vec![id]) + } + }; + + LedgerReadResponse::AccountsForRpc(rpc_id, res, account_query) } }, ), diff --git a/node/src/ledger/ledger_service.rs b/node/src/ledger/ledger_service.rs index 770d05061d..301ec0788c 100644 --- a/node/src/ledger/ledger_service.rs +++ b/node/src/ledger/ledger_service.rs @@ -638,6 +638,7 @@ impl LedgerCtx { &mut self, block: ArcBlockWithHash, pred_block: AppliedBlock, + skip_verification: Option, ) -> Result { openmina_core::info!(openmina_core::log::system_time(); kind = "LedgerService::block_apply", @@ -674,8 +675,7 @@ impl LedgerCtx { let result = staged_ledger .apply( - // TODO(binier): SEC - Some(SkipVerification::All), + skip_verification, constraint_constants(), Slot::from_u32(global_slot), diff, diff --git a/node/src/ledger/read/mod.rs b/node/src/ledger/read/mod.rs index 7267aa23d1..e3a1b8730c 100644 --- a/node/src/ledger/read/mod.rs +++ b/node/src/ledger/read/mod.rs @@ -18,7 +18,7 @@ use crate::account::AccountPublicKey; use crate::block_producer::vrf_evaluator::DelegatorTable; use crate::ledger::LedgerAddress; use crate::p2p::channels::rpc::StagedLedgerAuxAndPendingCoinbases; -use crate::rpc::RpcScanStateSummaryScanStateJob; +use crate::rpc::{AccountQuery, RpcScanStateSummaryScanStateJob}; #[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone, Copy)] pub enum LedgerReadKind { @@ -38,13 +38,13 @@ pub enum LedgerReadRequest { DelegatorTable(v2::LedgerHash, AccountPublicKey), // p2p rpcs GetNumAccounts(v2::LedgerHash), - GetAccounts(v2::LedgerHash, Vec), + GetAccounts(v2::LedgerHash, Vec, Option), GetChildHashesAtAddr(v2::LedgerHash, LedgerAddress), GetChildAccountsAtAddr(v2::LedgerHash, LedgerAddress), GetStagedLedgerAuxAndPendingCoinbases(LedgerReadStagedLedgerAuxAndPendingCoinbases), // rpcs ScanStateSummary(v2::MinaBaseStagedLedgerHashStableV1), - AccountsForRpc(RpcId, v2::LedgerHash, Option), + AccountsForRpc(RpcId, v2::LedgerHash, AccountQuery), } #[derive(Serialize, Deserialize, Debug, Clone)] @@ -53,13 +53,13 @@ pub enum LedgerReadResponse { DelegatorTable(Option), // p2p rpcs GetNumAccounts(Option<(u64, v2::LedgerHash)>), - GetAccounts(Vec), + GetAccounts(Vec, Option), GetChildHashesAtAddr(Option<(v2::LedgerHash, v2::LedgerHash)>), GetChildAccountsAtAddr(Option>), GetStagedLedgerAuxAndPendingCoinbases(Option>), // rpcs ScanStateSummary(Result>, String>), - AccountsForRpc(RpcId, Vec), + AccountsForRpc(RpcId, Vec, AccountQuery), } #[derive(Serialize, Deserialize, Debug, Clone)] diff --git a/node/src/ledger/write/mod.rs b/node/src/ledger/write/mod.rs index e51b4bbb70..88a8646a65 100644 --- a/node/src/ledger/write/mod.rs +++ b/node/src/ledger/write/mod.rs @@ -50,6 +50,7 @@ pub enum LedgerWriteRequest { BlockApply { block: ArcBlockWithHash, pred_block: AppliedBlock, + skip_verification: bool, }, Commit { ledgers_to_keep: BTreeSet, diff --git a/node/src/logger/logger_effects.rs b/node/src/logger/logger_effects.rs index 5ce0f7bcbc..6a4623b79b 100644 --- a/node/src/logger/logger_effects.rs +++ b/node/src/logger/logger_effects.rs @@ -18,14 +18,16 @@ struct ActionLoggerContext { time: redux::Timestamp, time_str: String, node_id: DisplayValue, + log_node_id: bool, } impl ActionLoggerContext { - fn new(time: redux::Timestamp, node_id: PeerId) -> Self { + fn new(time: redux::Timestamp, node_id: PeerId, log_node_id: bool) -> Self { ActionLoggerContext { time, time_str: time_to_str(time), node_id: display(node_id), + log_node_id, } } } @@ -39,6 +41,10 @@ impl EventContext for ActionLoggerContext { &self.time_str } + fn log_node_id(&self) -> bool { + self.log_node_id + } + fn node_id(&self) -> &'_ dyn Value { &self.node_id } @@ -46,7 +52,11 @@ impl EventContext for ActionLoggerContext { pub fn logger_effects(store: &Store, action: ActionWithMetaRef<'_>) { let (action, meta) = action.split(); - let context = ActionLoggerContext::new(meta.time(), store.state().p2p.my_id()); + let context = ActionLoggerContext::new( + meta.time(), + store.state().p2p.my_id(), + store.state().should_log_node_id(), + ); match action { Action::P2p(action) => match action { diff --git a/node/src/p2p/callbacks/mod.rs b/node/src/p2p/callbacks/mod.rs new file mode 100644 index 0000000000..d5e53fe032 --- /dev/null +++ b/node/src/p2p/callbacks/mod.rs @@ -0,0 +1,3 @@ +mod p2p_callbacks_actions; +pub use p2p_callbacks_actions::P2pCallbacksAction; +mod p2p_callbacks_reducer; diff --git a/node/src/p2p/callbacks/p2p_callbacks_actions.rs b/node/src/p2p/callbacks/p2p_callbacks_actions.rs new file mode 100644 index 0000000000..92078b9fac --- /dev/null +++ b/node/src/p2p/callbacks/p2p_callbacks_actions.rs @@ -0,0 +1,68 @@ +use openmina_core::ActionEvent; +use p2p::{ + channels::{ + rpc::{P2pRpcId, P2pRpcRequest, P2pRpcResponse}, + streaming_rpc::P2pStreamingRpcResponseFull, + }, + PeerId, +}; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone, ActionEvent)] +#[action_event(level = debug)] +pub enum P2pCallbacksAction { + P2pChannelsRpcReady { + peer_id: PeerId, + }, + P2pChannelsRpcTimeout { + peer_id: PeerId, + id: P2pRpcId, + }, + P2pChannelsRpcResponseReceived { + peer_id: PeerId, + id: P2pRpcId, + response: Option>, + }, + P2pChannelsRpcRequestReceived { + peer_id: PeerId, + id: P2pRpcId, + request: Box, + }, + + P2pChannelsStreamingRpcReady, + P2pChannelsStreamingRpcTimeout { + peer_id: PeerId, + id: P2pRpcId, + }, + P2pChannelsStreamingRpcResponseReceived { + peer_id: PeerId, + id: P2pRpcId, + response: Option, + }, + + P2pDisconnection { + peer_id: PeerId, + }, + RpcRespondBestTip { + peer_id: PeerId, + }, +} + +impl redux::EnablingCondition for P2pCallbacksAction { + fn is_enabled(&self, state: &crate::State, _time: redux::Timestamp) -> bool { + match self { + P2pCallbacksAction::P2pChannelsRpcReady { .. } => true, + P2pCallbacksAction::P2pChannelsRpcTimeout { .. } => true, + P2pCallbacksAction::P2pChannelsRpcResponseReceived { .. } => true, + P2pCallbacksAction::P2pChannelsRpcRequestReceived { .. } => true, + P2pCallbacksAction::P2pChannelsStreamingRpcReady => true, + P2pCallbacksAction::P2pChannelsStreamingRpcTimeout { .. } => true, + P2pCallbacksAction::P2pChannelsStreamingRpcResponseReceived { .. } => true, + P2pCallbacksAction::P2pDisconnection { .. } => true, + // TODO: what if we don't have best tip? + P2pCallbacksAction::RpcRespondBestTip { .. } => { + state.transition_frontier.best_tip().is_some() + } + } + } +} diff --git a/node/src/p2p/callbacks/p2p_callbacks_reducer.rs b/node/src/p2p/callbacks/p2p_callbacks_reducer.rs new file mode 100644 index 0000000000..fcabd0d449 --- /dev/null +++ b/node/src/p2p/callbacks/p2p_callbacks_reducer.rs @@ -0,0 +1,503 @@ +use ark_ff::fields::arithmetic::InvalidBigInt; +use mina_p2p_messages::v2::{MinaLedgerSyncLedgerAnswerStableV2, StateHash}; +use openmina_core::{block::BlockWithHash, bug_condition}; +use p2p::{ + channels::{ + best_tip::P2pChannelsBestTipAction, + rpc::{BestTipWithProof, P2pChannelsRpcAction, P2pRpcRequest, P2pRpcResponse}, + streaming_rpc::P2pStreamingRpcResponseFull, + }, + disconnection::{P2pDisconnectionAction, P2pDisconnectionReason}, + PeerId, +}; +use redux::{ActionMeta, ActionWithMeta, Dispatcher}; + +use crate::{ + p2p_ready, + snark_pool::candidate::SnarkPoolCandidateAction, + transition_frontier::sync::{ + ledger::{ + snarked::{ + PeerLedgerQueryError, PeerLedgerQueryResponse, + TransitionFrontierSyncLedgerSnarkedAction, + }, + staged::{PeerStagedLedgerPartsFetchError, TransitionFrontierSyncLedgerStagedAction}, + }, + PeerBlockFetchError, TransitionFrontierSyncAction, + }, + watched_accounts::{ + WatchedAccountLedgerInitialState, WatchedAccountsLedgerInitialStateGetError, + }, + Action, ConsensusAction, State, WatchedAccountsAction, +}; + +use super::P2pCallbacksAction; + +impl crate::State { + pub fn p2p_callback_reducer( + state_context: crate::Substate, + action: ActionWithMeta<&P2pCallbacksAction>, + ) { + let (action, meta) = action.split(); + let (dispatcher, state) = state_context.into_dispatcher_and_state(); + + match action { + P2pCallbacksAction::P2pChannelsRpcReady { peer_id } => { + let peer_id = *peer_id; + + dispatcher.push(P2pChannelsRpcAction::RequestSend { + peer_id, + id: 0, + request: Box::new(P2pRpcRequest::BestTipWithProof), + on_init: None, + }); + + dispatcher.push(TransitionFrontierSyncLedgerSnarkedAction::PeersQuery); + dispatcher.push(TransitionFrontierSyncLedgerStagedAction::PartsPeerFetchInit); + dispatcher.push(TransitionFrontierSyncAction::BlocksPeersQuery); + } + P2pCallbacksAction::P2pChannelsRpcTimeout { peer_id, id } => { + let peer_id = *peer_id; + let rpc_id = *id; + let Some(peer) = state.p2p.get_ready_peer(&peer_id) else { + bug_condition!("get_ready_peer({:?}) returned None", peer_id); + return; + }; + + let Some(rpc_kind) = peer.channels.rpc.pending_local_rpc_kind() else { + bug_condition!("peer: {:?} pending_local_rpc_kind() returned None", peer_id); + return; + }; + + dispatcher.push( + TransitionFrontierSyncLedgerSnarkedAction::PeerQueryAddressError { + peer_id, + rpc_id, + error: PeerLedgerQueryError::Timeout, + }, + ); + dispatcher.push( + TransitionFrontierSyncLedgerStagedAction::PartsPeerFetchError { + peer_id, + rpc_id, + error: PeerStagedLedgerPartsFetchError::Timeout, + }, + ); + dispatcher.push(TransitionFrontierSyncAction::BlocksPeerQueryError { + peer_id, + rpc_id, + error: PeerBlockFetchError::Timeout, + }); + dispatcher.push(P2pDisconnectionAction::Init { + peer_id, + reason: P2pDisconnectionReason::TransitionFrontierRpcTimeout(rpc_kind), + }); + } + P2pCallbacksAction::P2pChannelsRpcResponseReceived { + peer_id, + id, + response, + } => { + State::handle_rpc_channels_response(dispatcher, meta, *id, *peer_id, response); + dispatcher.push(TransitionFrontierSyncLedgerSnarkedAction::PeersQuery); + dispatcher.push(TransitionFrontierSyncLedgerStagedAction::PartsPeerFetchInit); + dispatcher.push(TransitionFrontierSyncAction::BlocksPeersQuery); + } + P2pCallbacksAction::P2pChannelsRpcRequestReceived { + peer_id, + id, + request, + } => { + State::handle_rpc_channels_request( + dispatcher, + state, + meta, + *request.clone(), + *peer_id, + *id, + ); + } + P2pCallbacksAction::P2pChannelsStreamingRpcReady => { + dispatcher.push(TransitionFrontierSyncLedgerStagedAction::PartsPeerFetchInit); + } + P2pCallbacksAction::P2pChannelsStreamingRpcTimeout { peer_id, id } => { + let peer_id = *peer_id; + let rpc_id = *id; + + let Some(peer) = state.p2p.get_ready_peer(&peer_id) else { + bug_condition!("get_ready_peer({:?}) returned None", peer_id); + return; + }; + let Some(rpc_kind) = peer.channels.streaming_rpc.pending_local_rpc_kind() else { + bug_condition!("peer: {:?} pending_local_rpc_kind() returned None", peer_id); + return; + }; + dispatcher.push( + TransitionFrontierSyncLedgerStagedAction::PartsPeerFetchError { + peer_id, + rpc_id, + error: PeerStagedLedgerPartsFetchError::Timeout, + }, + ); + dispatcher.push(P2pDisconnectionAction::Init { + peer_id, + reason: P2pDisconnectionReason::TransitionFrontierStreamingRpcTimeout(rpc_kind), + }); + } + P2pCallbacksAction::P2pChannelsStreamingRpcResponseReceived { + peer_id, + id, + response, + } => { + let peer_id = *peer_id; + let rpc_id = *id; + + match response { + None => { + dispatcher.push( + TransitionFrontierSyncLedgerStagedAction::PartsPeerFetchError { + peer_id, + rpc_id, + error: PeerStagedLedgerPartsFetchError::DataUnavailable, + }, + ); + } + Some(P2pStreamingRpcResponseFull::StagedLedgerParts(parts)) => { + dispatcher.push( + TransitionFrontierSyncLedgerStagedAction::PartsPeerFetchSuccess { + peer_id, + rpc_id, + parts: parts.clone(), + }, + ); + } + } + dispatcher.push(TransitionFrontierSyncLedgerStagedAction::PartsPeerFetchInit); + } + P2pCallbacksAction::P2pDisconnection { peer_id } => { + let peer_id = *peer_id; + + if let Some(s) = state.transition_frontier.sync.ledger() { + s.snarked() + .map(|s| { + s.peer_address_query_pending_rpc_ids(&peer_id) + .collect::>() + }) + .unwrap_or_default() + .into_iter() + .for_each(|rpc_id| { + dispatcher.push( + TransitionFrontierSyncLedgerSnarkedAction::PeerQueryAddressError { + peer_id, + rpc_id, + error: PeerLedgerQueryError::Disconnected, + }, + ); + }); + + if let Some(rpc_id) = s + .snarked() + .and_then(|s| s.peer_num_accounts_rpc_id(&peer_id)) + { + dispatcher.push( + TransitionFrontierSyncLedgerSnarkedAction::PeerQueryNumAccountsError { + peer_id, + rpc_id, + error: PeerLedgerQueryError::Disconnected, + }, + ); + } + + if let Some(rpc_id) = s.staged().and_then(|s| s.parts_fetch_rpc_id(&peer_id)) { + dispatcher.push( + TransitionFrontierSyncLedgerStagedAction::PartsPeerFetchError { + peer_id, + rpc_id, + error: PeerStagedLedgerPartsFetchError::Disconnected, + }, + ) + } + } + + state + .transition_frontier + .sync + .blocks_fetch_from_peer_pending_rpc_ids(&peer_id) + .for_each(|rpc_id| { + dispatcher.push(TransitionFrontierSyncAction::BlocksPeerQueryError { + peer_id, + rpc_id, + error: PeerBlockFetchError::Disconnected, + }); + }); + + state + .watched_accounts + .iter() + .filter_map(|(pub_key, a)| match &a.initial_state { + WatchedAccountLedgerInitialState::Pending { + peer_id: account_peer_id, + .. + } => { + if account_peer_id == &peer_id { + Some(WatchedAccountsAction::LedgerInitialStateGetError { + pub_key: pub_key.clone(), + error: + WatchedAccountsLedgerInitialStateGetError::PeerDisconnected, + }) + } else { + None + } + } + _ => None, + }) + .for_each(|action| dispatcher.push(action)); + + dispatcher.push(SnarkPoolCandidateAction::PeerPrune { peer_id }); + } + P2pCallbacksAction::RpcRespondBestTip { peer_id } => { + let Some(best_tip) = state.transition_frontier.best_tip() else { + bug_condition!("Best tip not found"); + return; + }; + + dispatcher.push(P2pChannelsBestTipAction::ResponseSend { + peer_id: *peer_id, + best_tip: best_tip.clone(), + }); + } + } + } + + fn handle_rpc_channels_request( + dispatcher: &mut Dispatcher, + state: &State, + meta: ActionMeta, + request: P2pRpcRequest, + peer_id: PeerId, + id: u64, + ) { + match request { + P2pRpcRequest::BestTipWithProof => { + let best_chain = &state.transition_frontier.best_chain; + let response = None.or_else(|| { + let best_tip = best_chain.last()?; + let mut chain_iter = best_chain.iter(); + let root_block = chain_iter.next()?; + // TODO(binier): cache body hashes + let Ok(body_hashes) = chain_iter + .map(|b| b.header().protocol_state.body.try_hash()) + .collect::>() + else { + openmina_core::error!(meta.time(); "P2pRpcRequest::BestTipWithProof: invalid protocol state"); + return None; + }; + + Some(BestTipWithProof { + best_tip: best_tip.block().clone(), + proof: (body_hashes, root_block.block().clone()), + }) + }); + let response = response.map(P2pRpcResponse::BestTipWithProof).map(Box::new); + dispatcher.push(P2pChannelsRpcAction::ResponseSend { + peer_id, + id, + response, + }); + } + P2pRpcRequest::Block(hash) => { + let best_chain = &state.transition_frontier.best_chain; + let response = best_chain + .iter() + .rev() + .find(|b| b.hash() == &hash) + .map(|b| b.block().clone()) + .map(P2pRpcResponse::Block) + .map(Box::new); + dispatcher.push(P2pChannelsRpcAction::ResponseSend { + peer_id, + id, + response, + }); + } + P2pRpcRequest::LedgerQuery(..) => { + // async ledger request will be triggered + // by `LedgerReadAction::FindTodos`. + } + P2pRpcRequest::StagedLedgerAuxAndPendingCoinbasesAtBlock(..) => { + // async ledger request will be triggered + // by `LedgerReadAction::FindTodos`. + } + P2pRpcRequest::Snark(job_id) => { + let job = state.snark_pool.get(&job_id); + let response = job + .and_then(|job| job.snark.as_ref()) + .map(|snark| snark.work.clone()) + .map(P2pRpcResponse::Snark) + .map(Box::new); + + dispatcher.push(P2pChannelsRpcAction::ResponseSend { + peer_id, + id, + response, + }); + } + P2pRpcRequest::InitialPeers => { + let p2p = p2p_ready!(state.p2p, meta.time()); + let peers = p2p + .peers + .iter() + .filter_map(|(_, v)| v.dial_opts.clone()) + .collect(); + let response = Some(Box::new(P2pRpcResponse::InitialPeers(peers))); + + dispatcher.push(P2pChannelsRpcAction::ResponseSend { + peer_id, + id, + response, + }); + } + } + } + + fn handle_rpc_channels_response( + dispatcher: &mut Dispatcher, + meta: ActionMeta, + id: u64, + peer_id: PeerId, + response: &Option>, + ) { + match response.as_deref() { + None => { + dispatcher.push( + TransitionFrontierSyncLedgerSnarkedAction::PeerQueryAddressError { + peer_id, + rpc_id: id, + error: PeerLedgerQueryError::DataUnavailable, + }, + ); + dispatcher.push( + TransitionFrontierSyncLedgerStagedAction::PartsPeerFetchError { + peer_id, + rpc_id: id, + error: PeerStagedLedgerPartsFetchError::DataUnavailable, + }, + ); + dispatcher.push(TransitionFrontierSyncAction::BlocksPeerQueryError { + peer_id, + rpc_id: id, + error: PeerBlockFetchError::DataUnavailable, + }); + } + Some(P2pRpcResponse::BestTipWithProof(resp)) => { + let (body_hashes, root_block) = &resp.proof; + + let (Ok(best_tip), Ok(root_block)) = ( + BlockWithHash::try_new(resp.best_tip.clone()), + BlockWithHash::try_new(root_block.clone()), + ) else { + openmina_core::error!(meta.time(); "P2pRpcResponse::BestTipWithProof: invalid blocks"); + return; + }; + + // reconstruct hashes + let Ok(hashes) = body_hashes + .iter() + .take(body_hashes.len().saturating_sub(1)) + .scan(root_block.hash.clone(), |pred_hash, body_hash| { + *pred_hash = match StateHash::try_from_hashes(pred_hash, body_hash) { + Ok(hash) => hash, + Err(_) => return Some(Err(InvalidBigInt)), + }; + Some(Ok(pred_hash.clone())) + }) + .collect::, _>>() + else { + openmina_core::error!(meta.time(); "P2pRpcResponse::BestTipWithProof: invalid hashes"); + return; + }; + + if let Some(pred_hash) = hashes.last() { + let expected_hash = &best_tip.block.header.protocol_state.previous_state_hash; + + if pred_hash != expected_hash { + openmina_core::warn!(meta.time(); + kind = "P2pRpcBestTipHashMismatch", + response = serde_json::to_string(&resp).ok(), + expected_hash = expected_hash.to_string(), + calculated_hash = pred_hash.to_string()); + return; + } + } + dispatcher.push(ConsensusAction::BlockChainProofUpdate { + hash: best_tip.hash, + chain_proof: (hashes, root_block), + }); + } + Some(P2pRpcResponse::LedgerQuery(answer)) => match answer { + MinaLedgerSyncLedgerAnswerStableV2::ChildHashesAre(left, right) => { + dispatcher.push( + TransitionFrontierSyncLedgerSnarkedAction::PeerQueryAddressSuccess { + peer_id, + rpc_id: id, + response: PeerLedgerQueryResponse::ChildHashes( + left.clone(), + right.clone(), + ), + }, + ); + } + MinaLedgerSyncLedgerAnswerStableV2::ContentsAre(accounts) => { + dispatcher.push( + TransitionFrontierSyncLedgerSnarkedAction::PeerQueryAddressSuccess { + peer_id, + rpc_id: id, + response: PeerLedgerQueryResponse::ChildAccounts( + accounts.iter().cloned().collect(), + ), + }, + ); + } + MinaLedgerSyncLedgerAnswerStableV2::NumAccounts(count, contents_hash) => { + dispatcher.push( + TransitionFrontierSyncLedgerSnarkedAction::PeerQueryNumAccountsSuccess { + peer_id, + rpc_id: id, + response: PeerLedgerQueryResponse::NumAccounts( + count.as_u64(), + contents_hash.clone(), + ), + }, + ); + } + }, + Some(P2pRpcResponse::StagedLedgerAuxAndPendingCoinbasesAtBlock(parts)) => { + dispatcher.push( + TransitionFrontierSyncLedgerStagedAction::PartsPeerFetchSuccess { + peer_id, + rpc_id: id, + parts: parts.clone(), + }, + ); + } + Some(P2pRpcResponse::Block(block)) => { + let Ok(block) = BlockWithHash::try_new(block.clone()) else { + openmina_core::error!(meta.time(); "P2pRpcResponse::Block: invalid block"); + return; + }; + dispatcher.push(TransitionFrontierSyncAction::BlocksPeerQuerySuccess { + peer_id, + rpc_id: id, + response: block, + }); + } + Some(P2pRpcResponse::Snark(snark)) => { + dispatcher.push(SnarkPoolCandidateAction::WorkReceived { + peer_id, + work: snark.clone(), + }); + } + Some(P2pRpcResponse::InitialPeers(_)) => {} + } + } +} diff --git a/node/src/p2p/mod.rs b/node/src/p2p/mod.rs index bcfe146103..aac743bfb1 100644 --- a/node/src/p2p/mod.rs +++ b/node/src/p2p/mod.rs @@ -13,6 +13,8 @@ pub mod disconnection; pub mod network; pub mod peer; +pub mod callbacks; + mod p2p_effects; pub use p2p_effects::*; use redux::EnablingCondition; diff --git a/node/src/p2p/p2p_effects.rs b/node/src/p2p/p2p_effects.rs index fcaaa45184..d6fb9e0146 100644 --- a/node/src/p2p/p2p_effects.rs +++ b/node/src/p2p/p2p_effects.rs @@ -1,43 +1,9 @@ -use ark_ff::fields::arithmetic::InvalidBigInt; -use mina_p2p_messages::v2::{MinaLedgerSyncLedgerAnswerStableV2, StateHash}; -use openmina_core::block::BlockWithHash; -use openmina_core::bug_condition; -use p2p::channels::streaming_rpc::{ - P2pChannelsStreamingRpcAction, P2pStreamingRpcRequest, P2pStreamingRpcResponseFull, +use super::P2pActionWithMeta; +use crate::{P2pAction, Service, Store}; +use p2p::{ + channels::P2pChannelsEffectfulAction, connection::P2pConnectionEffectfulAction, + P2pInitializeAction, }; -use p2p::channels::transaction::P2pChannelsTransactionAction; -use p2p::channels::P2pChannelsEffectfulAction; -use p2p::connection::P2pConnectionEffectfulAction; -use p2p::P2pInitializeAction; - -use crate::consensus::ConsensusAction; -use crate::rpc::RpcAction; -use crate::snark_pool::candidate::SnarkPoolCandidateAction; -use crate::snark_pool::SnarkPoolAction; -use crate::transition_frontier::sync::ledger::snarked::{ - PeerLedgerQueryError, PeerLedgerQueryResponse, TransitionFrontierSyncLedgerSnarkedAction, -}; -use crate::transition_frontier::sync::ledger::staged::{ - PeerStagedLedgerPartsFetchError, TransitionFrontierSyncLedgerStagedAction, -}; -use crate::transition_frontier::sync::{PeerBlockFetchError, TransitionFrontierSyncAction}; -use crate::watched_accounts::{ - WatchedAccountLedgerInitialState, WatchedAccountsAction, - WatchedAccountsLedgerInitialStateGetError, -}; -use crate::{p2p_ready, Service, Store, TransactionPoolAction}; - -use super::channels::best_tip::P2pChannelsBestTipAction; -use super::channels::rpc::{BestTipWithProof, P2pChannelsRpcAction, P2pRpcRequest, P2pRpcResponse}; -use super::channels::snark::P2pChannelsSnarkAction; -use super::channels::snark_job_commitment::P2pChannelsSnarkJobCommitmentAction; -use super::channels::P2pChannelsAction; -use super::connection::incoming::P2pConnectionIncomingAction; -use super::connection::outgoing::P2pConnectionOutgoingAction; -use super::connection::{P2pConnectionAction, P2pConnectionResponse}; -use super::disconnection::{P2pDisconnectionAction, P2pDisconnectionReason}; -use super::peer::P2pPeerAction; -use super::{P2pAction, P2pActionWithMeta}; pub fn node_p2p_effects(store: &mut Store, action: P2pActionWithMeta) { let (action, meta) = action.split(); @@ -49,592 +15,7 @@ pub fn node_p2p_effects(store: &mut Store, action: P2pActionWithM store.service().start_mio(); } } - P2pAction::Connection(action) => match action { - P2pConnectionAction::Outgoing(action) => match action { - P2pConnectionOutgoingAction::Error { - ref peer_id, - ref error, - } => { - let p2p = p2p_ready!(store.state().p2p, meta.time()); - if let Some(rpc_id) = p2p.peer_connection_rpc_id(peer_id) { - store.dispatch(RpcAction::P2pConnectionOutgoingError { - rpc_id, - error: error.clone(), - }); - } - } - P2pConnectionOutgoingAction::Success { ref peer_id } => { - let p2p = p2p_ready!(store.state().p2p, meta.time()); - if let Some(rpc_id) = p2p.peer_connection_rpc_id(peer_id) { - store.dispatch(RpcAction::P2pConnectionOutgoingSuccess { rpc_id }); - } - } - _ => {} - }, - P2pConnectionAction::Incoming(action) => match &action { - P2pConnectionIncomingAction::AnswerReady { peer_id, answer } => { - let p2p = p2p_ready!(store.state().p2p, meta.time()); - if let Some(rpc_id) = p2p.peer_connection_rpc_id(peer_id) { - store.dispatch(RpcAction::P2pConnectionIncomingRespond { - rpc_id, - response: P2pConnectionResponse::Accepted(answer.clone()), - }); - store.dispatch(P2pConnectionIncomingAction::AnswerSendSuccess { - peer_id: *peer_id, - }); - } - } - P2pConnectionIncomingAction::Error { peer_id, error } => { - let p2p = p2p_ready!(store.state().p2p, meta.time()); - if let Some(rpc_id) = p2p.peer_connection_rpc_id(peer_id) { - store.dispatch(RpcAction::P2pConnectionIncomingError { - rpc_id, - error: format!("{:?}", error), - }); - } - } - P2pConnectionIncomingAction::Success { peer_id } => { - let p2p = p2p_ready!(store.state().p2p, meta.time()); - if let Some(rpc_id) = p2p.peer_connection_rpc_id(peer_id) { - store.dispatch(RpcAction::P2pConnectionIncomingSuccess { rpc_id }); - } - } - _ => {} - }, - }, - P2pAction::Disconnection(action) => match action { - P2pDisconnectionAction::Init { .. } => {} - P2pDisconnectionAction::Finish { peer_id } => { - if let Some(s) = store.state().transition_frontier.sync.ledger() { - let snarked_ledger_num_accounts_rpc_id = s - .snarked() - .and_then(|s| s.peer_num_accounts_rpc_id(&peer_id)); - let snarked_ledger_address_rpc_ids = s - .snarked() - .map(|s| s.peer_address_query_pending_rpc_ids(&peer_id).collect()) - .unwrap_or(vec![]); - let staged_ledger_parts_fetch_rpc_id = - s.staged().and_then(|s| s.parts_fetch_rpc_id(&peer_id)); - - for rpc_id in snarked_ledger_address_rpc_ids { - store.dispatch( - TransitionFrontierSyncLedgerSnarkedAction::PeerQueryAddressError { - peer_id, - rpc_id, - error: PeerLedgerQueryError::Disconnected, - }, - ); - } - - if let Some(rpc_id) = snarked_ledger_num_accounts_rpc_id { - store.dispatch( - TransitionFrontierSyncLedgerSnarkedAction::PeerQueryNumAccountsError { - peer_id, - rpc_id, - error: PeerLedgerQueryError::Disconnected, - }, - ); - } - - if let Some(rpc_id) = staged_ledger_parts_fetch_rpc_id { - store.dispatch( - TransitionFrontierSyncLedgerStagedAction::PartsPeerFetchError { - peer_id, - rpc_id, - error: PeerStagedLedgerPartsFetchError::Disconnected, - }, - ); - } - } - - let blocks_fetch_rpc_ids = store - .state() - .transition_frontier - .sync - .blocks_fetch_from_peer_pending_rpc_ids(&peer_id) - .collect::>(); - - for rpc_id in blocks_fetch_rpc_ids { - store.dispatch(TransitionFrontierSyncAction::BlocksPeerQueryError { - peer_id, - rpc_id, - error: PeerBlockFetchError::Disconnected, - }); - } - - let actions = store - .state() - .watched_accounts - .iter() - .filter_map(|(pub_key, a)| match &a.initial_state { - WatchedAccountLedgerInitialState::Pending { - peer_id: account_peer_id, - .. - } => { - if account_peer_id == &peer_id { - Some(WatchedAccountsAction::LedgerInitialStateGetError { - pub_key: pub_key.clone(), - error: - WatchedAccountsLedgerInitialStateGetError::PeerDisconnected, - }) - } else { - None - } - } - _ => None, - }) - .collect::>(); - - for action in actions { - store.dispatch(action); - } - - store.dispatch(SnarkPoolCandidateAction::PeerPrune { peer_id }); - } - }, P2pAction::DisconnectionEffectful(action) => action.effects(&meta, store), - P2pAction::Channels(action) => match action { - P2pChannelsAction::MessageReceived(_) => { - // handled by reducer - } - P2pChannelsAction::BestTip(action) => { - if let P2pChannelsBestTipAction::RequestReceived { peer_id } = action { - if let Some(best_tip) = store.state().transition_frontier.best_tip() { - store.dispatch(P2pChannelsBestTipAction::ResponseSend { - peer_id, - best_tip: best_tip.clone(), - }); - } - } - } - P2pChannelsAction::Transaction(action) => { - match action { - P2pChannelsTransactionAction::Received { - peer_id: _, - transaction: _, - } => { - // TODO(binier): propagate tx info received to pool - } - P2pChannelsTransactionAction::Libp2pReceived { - peer_id: _, - transaction, - nonce: _, - } => { - store.dispatch(TransactionPoolAction::StartVerify { - // TODO: Take multiple transactions here - commands: [*transaction].into_iter().collect(), - from_rpc: None, - }); - } - _ => {} - } - } - P2pChannelsAction::Snark(action) => match action { - P2pChannelsSnarkAction::Received { peer_id, snark } => { - store.dispatch(SnarkPoolCandidateAction::InfoReceived { - peer_id, - info: *snark, - }); - } - P2pChannelsSnarkAction::Libp2pReceived { peer_id, snark, .. } => { - store.dispatch(SnarkPoolCandidateAction::WorkReceived { - peer_id, - work: *snark, - }); - } - _ => {} - }, - P2pChannelsAction::SnarkJobCommitment(action) => { - if let P2pChannelsSnarkJobCommitmentAction::Received { - peer_id, - commitment, - } = action - { - store.dispatch(SnarkPoolAction::CommitmentAdd { - commitment: *commitment, - sender: peer_id, - }); - } - } - P2pChannelsAction::Rpc(action) => { - match action { - P2pChannelsRpcAction::Ready { peer_id } => { - store.dispatch(P2pChannelsRpcAction::RequestSend { - peer_id, - id: 0, - request: Box::new(P2pRpcRequest::BestTipWithProof), - on_init: None, - }); - - store.dispatch(TransitionFrontierSyncLedgerSnarkedAction::PeersQuery); - store - .dispatch(TransitionFrontierSyncLedgerStagedAction::PartsPeerFetchInit); - store.dispatch(TransitionFrontierSyncAction::BlocksPeersQuery); - } - P2pChannelsRpcAction::Timeout { peer_id, id } => { - let Some(peer) = store.state().p2p.get_ready_peer(&peer_id) else { - bug_condition!("get_ready_peer({:?}) returned None", peer_id); - return; - }; - - let Some(rpc_kind) = peer.channels.rpc.pending_local_rpc_kind() else { - bug_condition!( - "peer: {:?} pending_local_rpc_kind() returned None", - peer_id - ); - return; - }; - - store.dispatch( - TransitionFrontierSyncLedgerSnarkedAction::PeerQueryAddressError { - peer_id, - rpc_id: id, - error: PeerLedgerQueryError::Timeout, - }, - ); - store.dispatch( - TransitionFrontierSyncLedgerStagedAction::PartsPeerFetchError { - peer_id, - rpc_id: id, - error: PeerStagedLedgerPartsFetchError::Timeout, - }, - ); - store.dispatch(TransitionFrontierSyncAction::BlocksPeerQueryError { - peer_id, - rpc_id: id, - error: PeerBlockFetchError::Timeout, - }); - store.dispatch(P2pDisconnectionAction::Init { - peer_id, - reason: P2pDisconnectionReason::TransitionFrontierRpcTimeout(rpc_kind), - }); - } - P2pChannelsRpcAction::ResponseReceived { - peer_id, - id, - response, - } => { - match response.as_deref() { - None => { - store.dispatch( - TransitionFrontierSyncLedgerSnarkedAction::PeerQueryAddressError { - peer_id, - rpc_id: id, - error: PeerLedgerQueryError::DataUnavailable, - }, - ); - store.dispatch( - TransitionFrontierSyncLedgerStagedAction::PartsPeerFetchError { - peer_id, - rpc_id: id, - error: PeerStagedLedgerPartsFetchError::DataUnavailable, - }, - ); - store.dispatch( - TransitionFrontierSyncAction::BlocksPeerQueryError { - peer_id, - rpc_id: id, - error: PeerBlockFetchError::DataUnavailable, - }, - ); - } - Some(P2pRpcResponse::BestTipWithProof(resp)) => { - let (body_hashes, root_block) = &resp.proof; - - let (Ok(best_tip), Ok(root_block)) = ( - BlockWithHash::try_new(resp.best_tip.clone()), - BlockWithHash::try_new(root_block.clone()), - ) else { - openmina_core::error!(meta.time(); "P2pRpcResponse::BestTipWithProof: invalid blocks"); - return; - }; - - // reconstruct hashes - let Ok(hashes) = body_hashes - .iter() - .take(body_hashes.len().saturating_sub(1)) - .scan(root_block.hash.clone(), |pred_hash, body_hash| { - *pred_hash = match StateHash::try_from_hashes( - pred_hash, body_hash, - ) { - Ok(hash) => hash, - Err(_) => return Some(Err(InvalidBigInt)), - }; - Some(Ok(pred_hash.clone())) - }) - .collect::, _>>() - else { - openmina_core::error!(meta.time(); "P2pRpcResponse::BestTipWithProof: invalid hashes"); - return; - }; - - if let Some(pred_hash) = hashes.last() { - let expected_hash = - &best_tip.block.header.protocol_state.previous_state_hash; - if pred_hash != expected_hash { - openmina_core::warn!(meta.time(); - kind = "P2pRpcBestTipHashMismatch", - response = serde_json::to_string(&resp).ok(), - expected_hash = expected_hash.to_string(), - calculated_hash = pred_hash.to_string()); - return; - } - } - store.dispatch(ConsensusAction::BlockChainProofUpdate { - hash: best_tip.hash, - chain_proof: (hashes, root_block), - }); - } - Some(P2pRpcResponse::LedgerQuery(answer)) => match answer { - MinaLedgerSyncLedgerAnswerStableV2::ChildHashesAre(left, right) => { - store.dispatch( - TransitionFrontierSyncLedgerSnarkedAction::PeerQueryAddressSuccess { - peer_id, - rpc_id: id, - response: PeerLedgerQueryResponse::ChildHashes( - left.clone(), - right.clone(), - ), - }, - ); - } - MinaLedgerSyncLedgerAnswerStableV2::ContentsAre(accounts) => { - store.dispatch( - TransitionFrontierSyncLedgerSnarkedAction::PeerQueryAddressSuccess { - peer_id, - rpc_id: id, - response: PeerLedgerQueryResponse::ChildAccounts( - accounts.iter().cloned().collect(), - ), - }, - ); - } - MinaLedgerSyncLedgerAnswerStableV2::NumAccounts( - count, - contents_hash, - ) => { - store.dispatch( - TransitionFrontierSyncLedgerSnarkedAction::PeerQueryNumAccountsSuccess { - peer_id, - rpc_id: id, - response: PeerLedgerQueryResponse::NumAccounts( - count.as_u64(), contents_hash.clone() - ), - }, - ); - } - }, - Some(P2pRpcResponse::StagedLedgerAuxAndPendingCoinbasesAtBlock( - parts, - )) => { - store.dispatch( - TransitionFrontierSyncLedgerStagedAction::PartsPeerFetchSuccess { - peer_id, - rpc_id: id, - parts: parts.clone(), - }, - ); - } - Some(P2pRpcResponse::Block(block)) => { - let Ok(block) = BlockWithHash::try_new(block.clone()) else { - openmina_core::error!(meta.time(); "P2pRpcResponse::Block: invalid block"); - return; - }; - store.dispatch( - TransitionFrontierSyncAction::BlocksPeerQuerySuccess { - peer_id, - rpc_id: id, - response: block, - }, - ); - } - Some(P2pRpcResponse::Snark(snark)) => { - store.dispatch(SnarkPoolCandidateAction::WorkReceived { - peer_id, - work: snark.clone(), - }); - } - Some(P2pRpcResponse::InitialPeers(_)) => {} - } - store.dispatch(TransitionFrontierSyncLedgerSnarkedAction::PeersQuery); - store.dispatch( - TransitionFrontierSyncLedgerStagedAction::PartsPeerFetchInit {}, - ); - store.dispatch(TransitionFrontierSyncAction::BlocksPeersQuery); - } - P2pChannelsRpcAction::RequestReceived { - peer_id, - id, - request, - } => { - match *request { - P2pRpcRequest::BestTipWithProof => { - let best_chain = &store.state().transition_frontier.best_chain; - let response = None.or_else(|| { - let best_tip = best_chain.last()?; - let mut chain_iter = best_chain.iter(); - let root_block = chain_iter.next()?; - // TODO(binier): cache body hashes - let Ok(body_hashes) = chain_iter - .map(|b| b.header().protocol_state.body.try_hash()) - .collect::>() - else { - openmina_core::error!(meta.time(); "P2pRpcRequest::BestTipWithProof: invalid protocol state"); - return None; - }; - - Some(BestTipWithProof { - best_tip: best_tip.block().clone(), - proof: (body_hashes, root_block.block().clone()), - }) - }); - let response = - response.map(P2pRpcResponse::BestTipWithProof).map(Box::new); - store.dispatch(P2pChannelsRpcAction::ResponseSend { - peer_id, - id, - response, - }); - } - P2pRpcRequest::Block(hash) => { - let best_chain = &store.state().transition_frontier.best_chain; - let response = best_chain - .iter() - .rev() - .find(|b| b.hash() == &hash) - .map(|b| b.block().clone()) - .map(P2pRpcResponse::Block) - .map(Box::new); - store.dispatch(P2pChannelsRpcAction::ResponseSend { - peer_id, - id, - response, - }); - } - P2pRpcRequest::LedgerQuery(..) => { - // async ledger request will be triggered - // by `LedgerReadAction::FindTodos`. - } - P2pRpcRequest::StagedLedgerAuxAndPendingCoinbasesAtBlock(..) => { - // async ledger request will be triggered - // by `LedgerReadAction::FindTodos`. - } - P2pRpcRequest::Snark(job_id) => { - let job = store.state().snark_pool.get(&job_id); - let response = job - .and_then(|job| job.snark.as_ref()) - .map(|snark| snark.work.clone()) - .map(P2pRpcResponse::Snark) - .map(Box::new); - - store.dispatch(P2pChannelsRpcAction::ResponseSend { - peer_id, - id, - response, - }); - } - P2pRpcRequest::InitialPeers => { - let p2p = p2p_ready!(store.state().p2p, meta.time()); - let peers = p2p - .peers - .iter() - .filter_map(|(_, v)| v.dial_opts.clone()) - .collect(); - let response = Some(Box::new(P2pRpcResponse::InitialPeers(peers))); - - store.dispatch(P2pChannelsRpcAction::ResponseSend { - peer_id, - id, - response, - }); - } - } - } - P2pChannelsRpcAction::Init { .. } => {} - P2pChannelsRpcAction::Pending { .. } => {} - P2pChannelsRpcAction::RequestSend { .. } => {} - P2pChannelsRpcAction::ResponsePending { .. } => {} - P2pChannelsRpcAction::ResponseSend { .. } => {} - } - } - P2pChannelsAction::StreamingRpc(action) => { - match action { - P2pChannelsStreamingRpcAction::Ready { .. } => { - store - .dispatch(TransitionFrontierSyncLedgerStagedAction::PartsPeerFetchInit); - } - P2pChannelsStreamingRpcAction::Timeout { peer_id, id } => { - let Some(peer) = store.state().p2p.get_ready_peer(&peer_id) else { - bug_condition!("get_ready_peer({:?}) returned None", peer_id); - return; - }; - let Some(rpc_kind) = peer.channels.streaming_rpc.pending_local_rpc_kind() - else { - bug_condition!( - "peer: {:?} pending_local_rpc_kind() returned None", - peer_id - ); - return; - }; - store.dispatch( - TransitionFrontierSyncLedgerStagedAction::PartsPeerFetchError { - peer_id, - rpc_id: id, - error: PeerStagedLedgerPartsFetchError::Timeout, - }, - ); - store.dispatch(P2pDisconnectionAction::Init { - peer_id, - reason: P2pDisconnectionReason::TransitionFrontierStreamingRpcTimeout( - rpc_kind, - ), - }); - } - P2pChannelsStreamingRpcAction::ResponseReceived { - peer_id, - id, - response, - } => { - match response { - None => { - store.dispatch( - TransitionFrontierSyncLedgerStagedAction::PartsPeerFetchError { - peer_id, - rpc_id: id, - error: PeerStagedLedgerPartsFetchError::DataUnavailable, - }, - ); - } - Some(P2pStreamingRpcResponseFull::StagedLedgerParts(parts)) => { - store.dispatch( - TransitionFrontierSyncLedgerStagedAction::PartsPeerFetchSuccess { - peer_id, - rpc_id: id, - parts, - }, - ); - } - } - store.dispatch( - TransitionFrontierSyncLedgerStagedAction::PartsPeerFetchInit {}, - ); - } - P2pChannelsStreamingRpcAction::RequestReceived { - peer_id: _, - id: _, - request, - } => { - match *request { - P2pStreamingRpcRequest::StagedLedgerParts(..) => { - // async ledger request will be triggered - // by `LedgerReadAction::FindTodos`. - } - } - } - _ => {} - } - } - }, P2pAction::ChannelsEffectful(action) => match action { P2pChannelsEffectfulAction::BestTip(action) => action.effects(&meta, store), P2pChannelsEffectfulAction::Transaction(action) => action.effects(&meta, store), @@ -643,26 +24,6 @@ pub fn node_p2p_effects(store: &mut Store, action: P2pActionWithM P2pChannelsEffectfulAction::Rpc(action) => action.effects(&meta, store), P2pChannelsEffectfulAction::SnarkJobCommitment(action) => action.effects(&meta, store), }, - P2pAction::Peer(action) => match action { - P2pPeerAction::Discovered { .. } - | P2pPeerAction::Ready { .. } - | P2pPeerAction::Remove { .. } => { - // handled by reducer - } - P2pPeerAction::BestTipUpdate { best_tip, .. } => { - store.dispatch(ConsensusAction::BlockReceived { - hash: best_tip.hash, - block: best_tip.block, - chain_proof: None, - }); - store.dispatch(TransitionFrontierSyncLedgerSnarkedAction::PeersQuery); - store.dispatch(TransitionFrontierSyncLedgerStagedAction::PartsPeerFetchInit); - store.dispatch(TransitionFrontierSyncAction::BlocksPeersQuery); - } - }, - P2pAction::Identify(_) => { - // handled by reducer - } P2pAction::Network(_action) => { #[cfg(feature = "p2p-libp2p")] _action.effects(&meta, store); @@ -671,5 +32,12 @@ pub fn node_p2p_effects(store: &mut Store, action: P2pActionWithM P2pConnectionEffectfulAction::Outgoing(action) => action.effects(&meta, store), P2pConnectionEffectfulAction::Incoming(action) => action.effects(&meta, store), }, + P2pAction::Peer(_) + | P2pAction::Channels(_) + | P2pAction::Connection(_) + | P2pAction::Disconnection(_) + | P2pAction::Identify(_) => { + // handled by reducer + } } } diff --git a/node/src/reducer.rs b/node/src/reducer.rs index 92538be208..dc838a265a 100644 --- a/node/src/reducer.rs +++ b/node/src/reducer.rs @@ -1,5 +1,5 @@ -use openmina_core::{error, Substate}; -use p2p::{P2pAction, P2pInitializeAction}; +use openmina_core::{bug_condition, error, Substate}; +use p2p::{P2pAction, P2pInitializeAction, P2pState}; use crate::{Action, ActionWithMeta, EventSourceAction, P2p, State}; @@ -10,7 +10,15 @@ pub fn reducer( ) { let meta = action.meta().clone(); match action.action() { - Action::CheckTimeouts(_) => {} + Action::CheckTimeouts(_) => { + if state.p2p.ready().is_some() { + if let Err(error) = + P2pState::p2p_timeout_dispatch(Substate::new(state, dispatcher), &meta) + { + bug_condition!("{}", error); + }; + } + } Action::EventSource(EventSourceAction::NewEvent { .. }) => {} Action::EventSource(_) => {} @@ -65,7 +73,7 @@ pub fn reducer( Action::TransactionPool(a) => { crate::transaction_pool::TransactionPoolState::reducer( Substate::new(state, dispatcher), - a, + meta.with_action(a), ); } Action::TransactionPoolEffect(_) => {} @@ -86,6 +94,9 @@ pub fn reducer( meta.with_action(a), ); } + Action::P2pCallbacks(action) => { + State::p2p_callback_reducer(Substate::new(state, dispatcher), meta.with_action(action)) + } } // must be the last. diff --git a/node/src/rpc/mod.rs b/node/src/rpc/mod.rs index e4288995c4..71492b05c9 100644 --- a/node/src/rpc/mod.rs +++ b/node/src/rpc/mod.rs @@ -5,7 +5,7 @@ use std::str::FromStr; use ark_ff::fields::arithmetic::InvalidBigInt; use ledger::scan_state::currency::{Amount, Balance, Fee, Nonce, Slot}; use ledger::scan_state::transaction_logic::signed_command::SignedCommandPayload; -use ledger::scan_state::transaction_logic::{self, signed_command, Memo}; +use ledger::scan_state::transaction_logic::{self, signed_command, valid, Memo}; use ledger::transaction_pool::{diff, ValidCommandWithHash}; use ledger::Account; use mina_p2p_messages::bigint::BigInt; @@ -14,6 +14,8 @@ use mina_p2p_messages::v2::{ MinaBaseUserCommandStableV2, MinaTransactionTransactionStableV2, SnarkWorkerWorkerRpcsVersionedGetWorkV2TResponse, StateHash, TransactionHash, }; +use openmina_core::block::AppliedBlock; +use openmina_core::consensus::ConsensusConstants; use openmina_node_account::AccountPublicKey; use p2p::bootstrap::P2pNetworkKadBootstrapStats; pub use rpc_state::*; @@ -74,11 +76,16 @@ pub enum RpcRequest { DiscoveryRoutingTable, DiscoveryBoostrapStats, TransactionPoolGet, - LedgerAccountsGet(Option), - TransactionInject(Vec), + LedgerAccountsGet(AccountQuery), + TransactionInject(Vec), TransitionFrontierUserCommandsGet, + BestChain(MaxLength), + ConsensusConstantsGet, + TransactionStatusGet(MinaBaseUserCommandStableV2), } +pub type MaxLength = u32; + #[derive(Serialize, Deserialize, Debug, Clone)] pub struct RpcInjectPayment { fee: u64, @@ -331,8 +338,20 @@ pub type RpcSnarkPoolGetResponse = Vec; pub type RpcSnarkPoolJobGetResponse = Option; pub type RpcSnarkerConfigGetResponse = Option; pub type RpcTransactionPoolResponse = Vec; -pub type RpcLedgerAccountsResponse = Vec; +pub type RpcLedgerSlimAccountsResponse = Vec; +pub type RpcLedgerAccountsResponse = Vec; pub type RpcTransitionFrontierUserCommandsResponse = Vec; +pub type RpcBestChainResponse = Vec; +pub type RpcConsensusConstantsGetResponse = ConsensusConstants; +pub type RpcTransactionStatusGetResponse = TransactionStatus; + +#[derive(Serialize, Deserialize, Debug, Clone, strum_macros::Display)] +#[strum(serialize_all = "SCREAMING_SNAKE_CASE")] +pub enum TransactionStatus { + Pending, + Included, + Unknown, +} // TODO(adonagy): rework this to handle all the possible user commands (enum..) #[derive(Serialize, Deserialize, Debug, Clone)] @@ -354,7 +373,7 @@ pub struct RpcTransactionInjectedPayment { pub enum RpcTransactionInjectedCommand { Payment(RpcTransactionInjectedPayment), Delegation, - Zkapp, + Zkapp(valid::UserCommand), } pub type RpcTransactionInjectSuccess = Vec; @@ -394,7 +413,9 @@ impl From for RpcTransactionInjectedCommand { } } } - transaction_logic::valid::UserCommand::ZkAppCommand(_) => todo!("inject zkapp"), + transaction_logic::valid::UserCommand::ZkAppCommand(_) => { + Self::Zkapp(value.data.clone()) + } } } } diff --git a/node/src/rpc/rpc_actions.rs b/node/src/rpc/rpc_actions.rs index fed855f0c9..8763f71a4e 100644 --- a/node/src/rpc/rpc_actions.rs +++ b/node/src/rpc/rpc_actions.rs @@ -1,9 +1,12 @@ use ledger::transaction_pool::{diff, ValidCommandWithHash}; use ledger::Account; +use mina_p2p_messages::v2::MinaBaseUserCommandStableV2; +use mina_p2p_messages::v2::TokenIdKeyHash; use openmina_core::block::AppliedBlock; use openmina_core::snark::SnarkJobId; use openmina_core::ActionEvent; use openmina_node_account::AccountPublicKey; +use p2p::PeerId; use serde::{Deserialize, Serialize}; use crate::external_snark_worker::SnarkWorkId; @@ -12,8 +15,8 @@ use crate::p2p::connection::outgoing::{P2pConnectionOutgoingError, P2pConnection use crate::p2p::connection::P2pConnectionResponse; use super::{ - ActionStatsQuery, RpcId, RpcInjectPayment, RpcScanStateSummaryGetQuery, - RpcScanStateSummaryScanStateJob, SyncStatsQuery, + ActionStatsQuery, RpcId, RpcScanStateSummaryGetQuery, RpcScanStateSummaryScanStateJob, + SyncStatsQuery, }; pub type RpcActionWithMeta = redux::ActionWithMeta; @@ -76,6 +79,11 @@ pub enum RpcAction { rpc_id: RpcId, response: P2pConnectionResponse, }, + P2pConnectionIncomingAnswerReady { + rpc_id: RpcId, + peer_id: PeerId, + answer: P2pConnectionResponse, + }, P2pConnectionIncomingError { rpc_id: RpcId, error: String, @@ -144,7 +152,7 @@ pub enum RpcAction { #[action_event(level = info)] LedgerAccountsGetInit { rpc_id: RpcId, - public_key: Option, + account_query: AccountQuery, }, #[action_event(level = info)] LedgerAccountsGetPending { @@ -154,11 +162,12 @@ pub enum RpcAction { LedgerAccountsGetSuccess { rpc_id: RpcId, accounts: Vec, + account_query: AccountQuery, }, #[action_event(level = info)] TransactionInjectInit { rpc_id: RpcId, - commands: Vec, + commands: Vec, }, #[action_event(level = info)] TransactionInjectPending { @@ -184,11 +193,31 @@ pub enum RpcAction { rpc_id: RpcId, }, + BestChain { + rpc_id: RpcId, + max_length: u32, + }, + ConsensusConstantsGet { + rpc_id: RpcId, + }, + + TransactionStatusGet { + rpc_id: RpcId, + tx: MinaBaseUserCommandStableV2, + }, + Finish { rpc_id: RpcId, }, } +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub enum AccountQuery { + SinglePublicKey(AccountPublicKey), + All, + PubKeyWithTokenId(AccountPublicKey, TokenIdKeyHash), +} + impl redux::EnablingCondition for RpcAction { fn is_enabled(&self, state: &crate::State, _time: redux::Timestamp) -> bool { match self { @@ -225,7 +254,8 @@ impl redux::EnablingCondition for RpcAction { .requests .get(rpc_id) .map_or(false, |v| v.status.is_init()), - RpcAction::P2pConnectionIncomingRespond { rpc_id, .. } => state + RpcAction::P2pConnectionIncomingRespond { rpc_id, .. } + | RpcAction::P2pConnectionIncomingAnswerReady { rpc_id, .. } => state .rpc .requests .get(rpc_id) @@ -267,6 +297,9 @@ impl redux::EnablingCondition for RpcAction { RpcAction::DiscoveryRoutingTable { .. } => true, RpcAction::DiscoveryBoostrapStats { .. } => true, RpcAction::TransactionPool { .. } => true, + RpcAction::ConsensusConstantsGet { .. } => true, + RpcAction::BestChain { .. } => state.transition_frontier.best_tip().is_some(), + RpcAction::TransactionStatusGet { .. } => true, RpcAction::LedgerAccountsGetInit { .. } => { state.transition_frontier.best_tip().is_some() } diff --git a/node/src/rpc/rpc_effects.rs b/node/src/rpc/rpc_effects.rs index 48f16c85b1..ea15efaf89 100644 --- a/node/src/rpc/rpc_effects.rs +++ b/node/src/rpc/rpc_effects.rs @@ -4,7 +4,7 @@ use std::time::Duration; use ledger::scan_state::currency::{Balance, Magnitude}; use ledger::Account; use mina_p2p_messages::rpc_kernel::QueryHeader; -use mina_p2p_messages::v2::MinaBaseTransactionStatusStableV2; +use mina_p2p_messages::v2::{MinaBaseTransactionStatusStableV2, TransactionHash}; use mina_signer::CompressedPubKey; use openmina_core::block::ArcBlockWithHash; use openmina_core::bug_condition; @@ -17,7 +17,7 @@ use crate::p2p::connection::outgoing::P2pConnectionOutgoingAction; use crate::p2p::connection::P2pConnectionResponse; use crate::rpc::{ AccountSlim, PeerConnectionStatus, RpcPeerInfo, RpcTransactionInjectResponse, - RpcTransactionInjectSuccess, + RpcTransactionInjectSuccess, TransactionStatus, }; use crate::snark_pool::SnarkPoolAction; use crate::transition_frontier::sync::ledger::TransitionFrontierSyncLedgerState; @@ -279,6 +279,17 @@ pub fn rpc_effects(store: &mut Store, action: RpcActionWithMeta) } } RpcAction::P2pConnectionIncomingPending { .. } => {} + RpcAction::P2pConnectionIncomingAnswerReady { + rpc_id, + answer, + peer_id, + } => { + store.dispatch(RpcAction::P2pConnectionIncomingRespond { + rpc_id, + response: answer, + }); + store.dispatch(P2pConnectionIncomingAction::AnswerSendSuccess { peer_id }); + } RpcAction::P2pConnectionIncomingRespond { rpc_id, response } => { let error = match &response { P2pConnectionResponse::Accepted(_) => None, @@ -656,7 +667,9 @@ pub fn rpc_effects(store: &mut Store, action: RpcActionWithMeta) .p2p .ready() .and_then(|p2p| p2p.network.scheduler.discovery_state()) - .and_then(|discovery_state| discovery_state.bootstrap_stats().cloned()); + .and_then(|discovery_state: &p2p::P2pNetworkKadState| { + discovery_state.bootstrap_stats().cloned() + }); respond_or_log!( store .service() @@ -672,71 +685,97 @@ pub fn rpc_effects(store: &mut Store, action: RpcActionWithMeta) meta.time() ) } - RpcAction::LedgerAccountsGetInit { rpc_id, public_key } => { + RpcAction::LedgerAccountsGetInit { + rpc_id, + account_query, + } => { let ledger_hash = if let Some(best_tip) = store.state().transition_frontier.best_tip() { best_tip.merkle_root_hash() } else { return; }; if store.dispatch(LedgerReadAction::Init { - request: LedgerReadRequest::AccountsForRpc(rpc_id, ledger_hash.clone(), public_key), + request: LedgerReadRequest::AccountsForRpc( + rpc_id, + ledger_hash.clone(), + account_query, + ), }) { store.dispatch(RpcAction::LedgerAccountsGetPending { rpc_id }); } } RpcAction::LedgerAccountsGetPending { .. } => {} - RpcAction::LedgerAccountsGetSuccess { rpc_id, accounts } => { + RpcAction::LedgerAccountsGetSuccess { + rpc_id, + accounts, + account_query, + } => { // TODO(adonagy): maybe something more effective? - let mut accounts: BTreeMap = accounts - .into_iter() - .map(|acc| (acc.public_key.clone(), acc)) - .collect(); - let nonces_and_amount = store - .state() - .transaction_pool - .get_pending_amount_and_nonce(); + match account_query { + super::AccountQuery::SinglePublicKey(_pk) => todo!(), + // all the accounts for the FE in Slim form + super::AccountQuery::All => { + let mut accounts: BTreeMap = accounts + .into_iter() + .map(|acc| (acc.public_key.clone(), acc)) + .collect(); + let nonces_and_amount = store + .state() + .transaction_pool + .get_pending_amount_and_nonce(); - nonces_and_amount - .iter() - .for_each(|(account_id, (nonce, amount))| { - if let Some(account) = accounts.get_mut(&account_id.public_key) { - if let Some(nonce) = nonce { - if nonce >= &account.nonce { - // increment the last nonce in the pool - account.nonce = nonce.incr(); + nonces_and_amount + .iter() + .for_each(|(account_id, (nonce, amount))| { + if let Some(account) = accounts.get_mut(&account_id.public_key) { + if let Some(nonce) = nonce { + if nonce >= &account.nonce { + // increment the last nonce in the pool + account.nonce = nonce.incr(); + } + } + account.balance = account + .balance + .sub_amount(*amount) + .unwrap_or(Balance::zero()); } - } - account.balance = account - .balance - .sub_amount(*amount) - .unwrap_or(Balance::zero()); - } - }); + }); - let accounts = accounts - .into_values() - .map(|v| v.into()) - .collect::>(); + let accounts = accounts + .into_values() + .map(|v| v.into()) + .collect::>(); - respond_or_log!( - store.service().respond_ledger_accounts(rpc_id, accounts), - meta.time() - ) + respond_or_log!( + store + .service() + .respond_ledger_slim_accounts(rpc_id, accounts), + meta.time() + ) + } + // for the graphql endpoint + super::AccountQuery::PubKeyWithTokenId(..) => { + respond_or_log!( + store.service().respond_ledger_accounts(rpc_id, accounts), + meta.time() + ) + } + } } RpcAction::TransactionInjectInit { rpc_id, commands } => { store.dispatch(RpcAction::TransactionInjectPending { rpc_id }); // sort the commadns by nonce - let Ok(commands) = commands - .into_iter() - .map(|c| c.try_into()) - .collect::>() - else { - return; - }; + // let Ok(commands) = commands + // .into_iter() + // .map(|c| c.try_into()) + // .collect::>() + // else { + // return; + // }; store.dispatch(TransactionPoolAction::StartVerify { - commands, + commands: commands.into_iter().collect(), from_rpc: Some(rpc_id), }); } @@ -792,6 +831,82 @@ pub fn rpc_effects(store: &mut Store, action: RpcActionWithMeta) meta.time() ) } + RpcAction::BestChain { rpc_id, max_length } => { + let best_chain = store + .state() + .transition_frontier + .best_chain + .iter() + .rev() + .take(max_length as usize) + .cloned() + .rev() + .collect(); + + respond_or_log!( + store.service().respond_best_chain(rpc_id, best_chain), + meta.time() + ) + } + RpcAction::ConsensusConstantsGet { rpc_id } => { + let response = store.state().config.consensus_constants.clone(); + respond_or_log!( + store + .service() + .respond_consensus_constants(rpc_id, response), + meta.time() + ) + } + RpcAction::TransactionStatusGet { rpc_id, tx } => { + // Check if the transaction is in the pool, if it is, return PENDING + let tx_hash = tx.hash().ok(); + + let in_tx_pool = store + .state() + .transaction_pool + .get_all_transactions() + .iter() + .any(|tx_with_hash| { + Some(TransactionHash::from(tx_with_hash.hash.as_ref())) == tx_hash + }); + + if in_tx_pool { + respond_or_log!( + store + .service() + .respond_transaction_status(rpc_id, TransactionStatus::Pending), + meta.time() + ); + return; + } + + let in_transition_frontier = if let Some(hash) = tx_hash { + store + .state() + .transition_frontier + .contains_transaction(&hash) + } else { + false + }; + + // Check whether the transaction is in the transition frontier, if it is, return INCLUDED + if in_transition_frontier { + respond_or_log!( + store + .service() + .respond_transaction_status(rpc_id, TransactionStatus::Included), + meta.time() + ) + // Otherwise, return UNKNOWN + } else { + respond_or_log!( + store + .service() + .respond_transaction_status(rpc_id, TransactionStatus::Unknown), + meta.time() + ) + } + } RpcAction::Finish { .. } => {} } } diff --git a/node/src/rpc/rpc_reducer.rs b/node/src/rpc/rpc_reducer.rs index 4a6f727491..ce4051cdbc 100644 --- a/node/src/rpc/rpc_reducer.rs +++ b/node/src/rpc/rpc_reducer.rs @@ -109,9 +109,12 @@ impl RpcState { self.requests.remove(rpc_id); } RpcAction::TransactionPool { .. } => {} - RpcAction::LedgerAccountsGetInit { rpc_id, public_key } => { + RpcAction::LedgerAccountsGetInit { + rpc_id, + account_query, + } => { let rpc_state = RpcRequestState { - req: RpcRequest::LedgerAccountsGet(public_key.clone()), + req: RpcRequest::LedgerAccountsGet(account_query.clone()), status: RpcRequestStatus::Init { time: meta.time() }, data: Default::default(), }; @@ -165,6 +168,10 @@ impl RpcState { }; } RpcAction::TransitionFrontierUserCommandsGet { .. } => {} + RpcAction::BestChain { .. } => {} + RpcAction::ConsensusConstantsGet { .. } => {} + RpcAction::TransactionStatusGet { .. } => {} + RpcAction::P2pConnectionIncomingAnswerReady { .. } => {} } } } diff --git a/node/src/rpc/rpc_service.rs b/node/src/rpc/rpc_service.rs index 94b762c14e..08e0817dcf 100644 --- a/node/src/rpc/rpc_service.rs +++ b/node/src/rpc/rpc_service.rs @@ -1,3 +1,4 @@ +use openmina_core::consensus::ConsensusConstants; use serde::{Deserialize, Serialize}; use thiserror::Error; @@ -5,13 +6,14 @@ use crate::p2p::connection::P2pConnectionResponse; use crate::State; use super::{ - RpcActionStatsGetResponse, RpcBlockProducerStatsGetResponse, RpcDiscoveryBoostrapStatsResponse, - RpcDiscoveryRoutingTableResponse, RpcHealthCheckResponse, RpcId, RpcLedgerAccountsResponse, - RpcMessageProgressResponse, RpcP2pConnectionOutgoingResponse, RpcPeersGetResponse, - RpcReadinessCheckResponse, RpcScanStateSummaryGetResponse, RpcSnarkPoolGetResponse, - RpcSnarkPoolJobGetResponse, RpcSnarkerJobCommitResponse, RpcSnarkerJobSpecResponse, - RpcSnarkerWorkersResponse, RpcStatusGetResponse, RpcSyncStatsGetResponse, - RpcTransactionInjectResponse, RpcTransactionPoolResponse, + RpcActionStatsGetResponse, RpcBestChainResponse, RpcBlockProducerStatsGetResponse, + RpcDiscoveryBoostrapStatsResponse, RpcDiscoveryRoutingTableResponse, RpcHealthCheckResponse, + RpcId, RpcLedgerAccountsResponse, RpcLedgerSlimAccountsResponse, RpcMessageProgressResponse, + RpcP2pConnectionOutgoingResponse, RpcPeersGetResponse, RpcReadinessCheckResponse, + RpcScanStateSummaryGetResponse, RpcSnarkPoolGetResponse, RpcSnarkPoolJobGetResponse, + RpcSnarkerJobCommitResponse, RpcSnarkerJobSpecResponse, RpcSnarkerWorkersResponse, + RpcStatusGetResponse, RpcSyncStatsGetResponse, RpcTransactionInjectResponse, + RpcTransactionPoolResponse, RpcTransactionStatusGetResponse, RpcTransitionFrontierUserCommandsResponse, }; @@ -150,6 +152,11 @@ pub trait RpcService { rpc_id: RpcId, response: RpcTransactionPoolResponse, ) -> Result<(), RespondError>; + fn respond_ledger_slim_accounts( + &mut self, + rpc_id: RpcId, + response: RpcLedgerSlimAccountsResponse, + ) -> Result<(), RespondError>; fn respond_ledger_accounts( &mut self, rpc_id: RpcId, @@ -165,4 +172,19 @@ pub trait RpcService { rpc_id: RpcId, response: RpcTransitionFrontierUserCommandsResponse, ) -> Result<(), RespondError>; + fn respond_best_chain( + &mut self, + rpc_id: RpcId, + response: RpcBestChainResponse, + ) -> Result<(), RespondError>; + fn respond_consensus_constants( + &mut self, + rpc_id: RpcId, + response: ConsensusConstants, + ) -> Result<(), RespondError>; + fn respond_transaction_status( + &mut self, + rpc_id: RpcId, + response: RpcTransactionStatusGetResponse, + ) -> Result<(), RespondError>; } diff --git a/node/src/rpc/rpc_state.rs b/node/src/rpc/rpc_state.rs index e622a71971..bffd101a7a 100644 --- a/node/src/rpc/rpc_state.rs +++ b/node/src/rpc/rpc_state.rs @@ -2,10 +2,9 @@ use std::collections::BTreeMap; use mina_p2p_messages::v2; use openmina_core::block::AppliedBlock; -use openmina_node_account::AccountPublicKey; use serde::{Deserialize, Serialize}; -use super::{RpcId, RpcRequest}; +use super::{AccountQuery, RpcId, RpcRequest}; #[derive(Serialize, Deserialize, Debug, Clone)] pub struct RpcRequestState { @@ -85,7 +84,7 @@ impl RpcState { pub fn accounts_request_rpc_ids( &self, - ) -> impl Iterator, &RpcRequestStatus)> + '_ { + ) -> impl Iterator + '_ { self.requests.iter().filter_map(|(id, req)| { if let RpcRequest::LedgerAccountsGet(account) = &req.req { Some((*id, account.clone(), &req.status)) diff --git a/node/src/state.rs b/node/src/state.rs index 3681892dbb..f0bc369031 100644 --- a/node/src/state.rs +++ b/node/src/state.rs @@ -1,9 +1,22 @@ -use openmina_core::block::ArcBlockWithHash; -use openmina_core::consensus::ConsensusConstants; -use openmina_core::{constants::constraint_constants, error, ChainId}; -use p2p::bootstrap::P2pNetworkKadBootstrapState; -use p2p::network::identify::P2pNetworkIdentifyState; -use p2p::{P2pConfig, P2pNetworkSchedulerState, P2pPeerState, P2pPeerStatusReady, PeerId}; +use std::sync::Arc; + +use mina_p2p_messages::v2::{MinaBaseUserCommandStableV2, MinaBlockBlockStableV2}; + +use openmina_core::block::BlockWithHash; +use openmina_core::requests::RpcId; +use openmina_core::snark::{Snark, SnarkInfo}; +use openmina_core::{ + block::ArcBlockWithHash, consensus::ConsensusConstants, constants::constraint_constants, error, + snark::SnarkJobCommitment, ChainId, +}; +use p2p::channels::rpc::{P2pRpcId, P2pRpcRequest, P2pRpcResponse}; +use p2p::channels::streaming_rpc::P2pStreamingRpcResponseFull; +use p2p::connection::outgoing::P2pConnectionOutgoingError; +use p2p::connection::P2pConnectionResponse; +use p2p::{ + bootstrap::P2pNetworkKadBootstrapState, network::identify::P2pNetworkIdentifyState, + P2pCallbacks, P2pConfig, P2pNetworkSchedulerState, P2pPeerState, P2pPeerStatusReady, PeerId, +}; use redux::{ActionMeta, EnablingCondition, Timestamp}; use serde::{Deserialize, Serialize}; use snark::block_verify::SnarkBlockVerifyState; @@ -11,13 +24,14 @@ use snark::user_command_verify::SnarkUserCommandVerifyState; use snark::work_verify::SnarkWorkVerifyState; pub use crate::block_producer::BlockProducerState; -use crate::config::GlobalConfig; pub use crate::consensus::ConsensusState; use crate::external_snark_worker::ExternalSnarkWorkers; pub use crate::ledger::LedgerState; +use crate::p2p::callbacks::P2pCallbacksAction; pub use crate::p2p::P2pState; pub use crate::rpc::RpcState; pub use crate::snark::SnarkState; +use crate::snark_pool::candidate::SnarkPoolCandidateAction; pub use crate::snark_pool::candidate::SnarkPoolCandidatesState; pub use crate::snark_pool::SnarkPoolState; use crate::transaction_pool::TransactionPoolState; @@ -28,8 +42,9 @@ use crate::transition_frontier::sync::ledger::TransitionFrontierSyncLedgerState; use crate::transition_frontier::sync::TransitionFrontierSyncState; pub use crate::transition_frontier::TransitionFrontierState; pub use crate::watched_accounts::WatchedAccountsState; -use crate::ActionWithMeta; pub use crate::Config; +use crate::{config::GlobalConfig, SnarkPoolAction}; +use crate::{ActionWithMeta, ConsensusAction, RpcAction, TransactionPoolAction}; #[derive(Serialize, Deserialize, Debug, Clone)] pub struct State { @@ -54,7 +69,7 @@ pub struct State { } // Substate accessors that will be used in reducers -use openmina_core::impl_substate_access; +use openmina_core::{impl_substate_access, SubstateAccess}; impl_substate_access!(State, SnarkState, snark); impl_substate_access!(State, SnarkBlockVerifyState, snark.block_verify); @@ -164,6 +179,16 @@ impl openmina_core::SubstateAccess for } } +impl SubstateAccess for State { + fn substate(&self) -> openmina_core::SubstateResult<&State> { + Ok(self) + } + + fn substate_mut(&mut self) -> openmina_core::SubstateResult<&mut State> { + Ok(self) + } +} + macro_rules! impl_p2p_state_access { ($state:ty, $substate_type:ty) => { impl openmina_core::SubstateAccess<$substate_type> for $state { @@ -256,6 +281,10 @@ impl State { self.cur_slot(|b| b.global_slot()) } + pub fn current_slot(&self) -> Option { + self.cur_slot(|b| b.global_slot() % b.constants().slots_per_epoch.as_u32()) + } + pub fn cur_global_slot_since_genesis(&self) -> Option { self.cur_slot(|b| b.global_slot_since_genesis()) } @@ -273,6 +302,10 @@ impl State { self.current_epoch() <= Some(epoch) }) } + + pub fn should_log_node_id(&self) -> bool { + self.config.testing_run + } } #[serde_with::serde_as] @@ -318,10 +351,112 @@ impl P2p { let P2p::Pending(config) = self else { return Err(P2pInitializationError::AlreadyInitialized); }; - *self = P2p::Ready(P2pState::new(config.clone(), chain_id)); + + let callbacks = Self::p2p_callbacks(); + *self = P2p::Ready(P2pState::new(config.clone(), callbacks, chain_id)); Ok(()) } + fn p2p_callbacks() -> P2pCallbacks { + P2pCallbacks { + on_p2p_channels_transaction_libp2p_received: Some(redux::callback!( + on_p2p_channels_transaction_libp2p_received(transaction: Box) -> crate::Action{ + TransactionPoolAction::StartVerify { commands: std::iter::once(*transaction).collect(), from_rpc: None } + } + )), + on_p2p_channels_snark_job_commitment_received: Some(redux::callback!( + on_p2p_channels_snark_job_commitment_received((peer_id: PeerId, commitment: Box)) -> crate::Action{ + SnarkPoolAction::CommitmentAdd { commitment: *commitment, sender: peer_id } + } + )), + on_p2p_channels_snark_received: Some(redux::callback!( + on_p2p_channels_snark_received((peer_id: PeerId, snark: Box)) -> crate::Action{ + SnarkPoolCandidateAction::InfoReceived { peer_id, info: *snark } + } + )), + on_p2p_channels_snark_libp2p_received: Some(redux::callback!( + on_p2p_channels_snark_received((peer_id: PeerId, snark: Box)) -> crate::Action{ + SnarkPoolCandidateAction::WorkReceived { peer_id, work: *snark } + } + )), + on_p2p_channels_streaming_rpc_ready: Some(redux::callback!( + on_p2p_channels_streaming_rpc_ready(_var: ()) -> crate::Action{ + P2pCallbacksAction::P2pChannelsStreamingRpcReady + } + )), + on_p2p_channels_best_tip_request_received: Some(redux::callback!( + on_p2p_channels_best_tip_request_received(peer_id: PeerId) -> crate::Action{ + P2pCallbacksAction::RpcRespondBestTip { peer_id } + } + )), + on_p2p_disconnection_finish: Some(redux::callback!( + on_p2p_disconnection_finish(peer_id: PeerId) -> crate::Action{ + P2pCallbacksAction::P2pDisconnection { peer_id } + } + )), + on_p2p_connection_outgoing_error: Some(redux::callback!( + on_p2p_connection_outgoing_error((rpc_id: RpcId, error: P2pConnectionOutgoingError)) -> crate::Action{ + RpcAction::P2pConnectionOutgoingError { rpc_id, error } + } + )), + on_p2p_connection_outgoing_success: Some(redux::callback!( + on_p2p_connection_outgoing_success(rpc_id: RpcId) -> crate::Action{ + RpcAction::P2pConnectionOutgoingSuccess { rpc_id } + } + )), + on_p2p_connection_incoming_error: Some(redux::callback!( + on_p2p_connection_incoming_error((rpc_id: RpcId, error: String)) -> crate::Action{ + RpcAction::P2pConnectionIncomingError { rpc_id, error } + } + )), + on_p2p_connection_incoming_success: Some(redux::callback!( + on_p2p_connection_incoming_success(rpc_id: RpcId) -> crate::Action{ + RpcAction::P2pConnectionIncomingSuccess { rpc_id } + } + )), + on_p2p_connection_incoming_answer_ready: Some(redux::callback!( + on_p2p_connection_incoming_answer_ready((rpc_id: RpcId, peer_id: PeerId, answer: P2pConnectionResponse)) -> crate::Action{ + RpcAction::P2pConnectionIncomingAnswerReady { rpc_id, answer, peer_id } + } + )), + on_p2p_peer_best_tip_update: Some(redux::callback!( + on_p2p_peer_best_tip_update(best_tip: BlockWithHash>) -> crate::Action{ + ConsensusAction::P2pBestTipUpdate{best_tip} + } + )), + on_p2p_channels_rpc_ready: Some(redux::callback!( + on_p2p_channels_rpc_ready(peer_id: PeerId) -> crate::Action{ + P2pCallbacksAction::P2pChannelsRpcReady {peer_id} + } + )), + on_p2p_channels_rpc_timeout: Some(redux::callback!( + on_p2p_channels_rpc_timeout((peer_id: PeerId, id: P2pRpcId)) -> crate::Action{ + P2pCallbacksAction::P2pChannelsRpcTimeout { peer_id, id } + } + )), + on_p2p_channels_rpc_response_received: Some(redux::callback!( + on_p2p_channels_rpc_response_received((peer_id: PeerId, id: P2pRpcId, response: Option>)) -> crate::Action{ + P2pCallbacksAction::P2pChannelsRpcResponseReceived {peer_id, id, response} + } + )), + on_p2p_channels_rpc_request_received: Some(redux::callback!( + on_p2p_channels_rpc_request_received((peer_id: PeerId, id: P2pRpcId, request: Box)) -> crate::Action{ + P2pCallbacksAction::P2pChannelsRpcRequestReceived {peer_id, id, request} + } + )), + on_p2p_channels_streaming_rpc_response_received: Some(redux::callback!( + on_p2p_channels_streaming_rpc_response_received((peer_id: PeerId, id: P2pRpcId, response: Option)) -> crate::Action{ + P2pCallbacksAction::P2pChannelsStreamingRpcResponseReceived {peer_id, id, response} + } + )), + on_p2p_channels_streaming_rpc_timeout: Some(redux::callback!( + on_p2p_channels_streaming_rpc_timeout((peer_id: PeerId, id: P2pRpcId)) -> crate::Action{ + P2pCallbacksAction::P2pChannelsStreamingRpcTimeout { peer_id, id } + } + )), + } + } + pub fn ready(&self) -> Option<&P2pState> { if let P2p::Ready(state) = self { Some(state) diff --git a/node/src/transaction_pool/mod.rs b/node/src/transaction_pool/mod.rs index 8846121642..4f4ddfc220 100644 --- a/node/src/transaction_pool/mod.rs +++ b/node/src/transaction_pool/mod.rs @@ -20,6 +20,7 @@ use std::{ collections::{BTreeMap, BTreeSet, HashMap}, sync::Arc, }; +use transaction_pool_actions::TransactionPoolActionWithMetaRef; pub mod transaction_pool_actions; @@ -106,13 +107,13 @@ impl TransactionPoolState { } } - pub fn reducer(mut state: crate::Substate, action: &TransactionPoolAction) { + pub fn reducer(mut state: crate::Substate, action: TransactionPoolActionWithMetaRef<'_>) { // Uncoment following line to save actions to `/tmp/pool.bin` // Self::save_actions(&mut state); let substate = state.get_substate_mut().unwrap(); if let Some(file) = substate.file.as_mut() { - postcard::to_io(action, file).unwrap(); + postcard::to_io(&action, file).unwrap(); }; Self::handle_action(state, action) @@ -125,7 +126,11 @@ impl TransactionPoolState { )) } - fn handle_action(mut state: crate::Substate, action: &TransactionPoolAction) { + fn handle_action( + mut state: crate::Substate, + action: TransactionPoolActionWithMetaRef<'_>, + ) { + let (action, meta) = action.split(); let Some((global_slot, global_slot_from_genesis)) = // TODO: remove usage of `unsafe_get_state` Self::global_slots(state.unsafe_get_state()) @@ -293,6 +298,7 @@ impl TransactionPoolState { // Note(adonagy): Action for rebroadcast, in his action we can use forget_check match substate.pool.unsafe_apply( + meta.time(), global_slot_from_genesis, global_slot, &diff, @@ -444,6 +450,7 @@ mod tests { use super::*; use crate::State; use redux::Dispatcher; + use transaction_pool_actions::TransactionPoolActionWithMeta; #[allow(unused)] #[test] @@ -454,13 +461,16 @@ mod tests { let (mut state, rest) = postcard::take_from_bytes::(slice).unwrap(); let mut slice = rest; - while let Ok((action, rest)) = postcard::take_from_bytes::(slice) { + while let Ok((action, rest)) = + postcard::take_from_bytes::(slice) + { slice = rest; let mut dispatcher = Dispatcher::new(); let state = crate::Substate::::new(&mut state, &mut dispatcher); + let (action, meta) = action.split(); - TransactionPoolState::handle_action(state, &action); + TransactionPoolState::handle_action(state, meta.with_action(&action)); } } } diff --git a/node/src/transaction_pool/transaction_pool_actions.rs b/node/src/transaction_pool/transaction_pool_actions.rs index c80cdd6ac9..0bffbbd799 100644 --- a/node/src/transaction_pool/transaction_pool_actions.rs +++ b/node/src/transaction_pool/transaction_pool_actions.rs @@ -19,6 +19,9 @@ use crate::ledger::LedgerService; use super::PendingId; +pub type TransactionPoolActionWithMeta = redux::ActionWithMeta; +pub type TransactionPoolActionWithMetaRef<'a> = redux::ActionWithMeta<&'a TransactionPoolAction>; + #[derive(Serialize, Deserialize, Debug, Clone, ActionEvent)] #[action_event(level = info)] pub enum TransactionPoolAction { diff --git a/node/src/transition_frontier/sync/mod.rs b/node/src/transition_frontier/sync/mod.rs index 31fd12daa7..0bf4b1c16b 100644 --- a/node/src/transition_frontier/sync/mod.rs +++ b/node/src/transition_frontier/sync/mod.rs @@ -25,3 +25,8 @@ pub enum SyncError { #[error("sync failed due to block({}, {}) application error: {1}", .0.height(), .0.hash())] BlockApplyFailed(ArcBlockWithHash, String), } + +/// How close to the best tip we have to be for the full +/// verification of proofs contained in the block +/// body (zkApp txns and completed works) to be enabled. +const CATCHUP_BLOCK_VERIFY_TAIL_LENGTH: usize = 5; diff --git a/node/src/transition_frontier/sync/transition_frontier_sync_effects.rs b/node/src/transition_frontier/sync/transition_frontier_sync_effects.rs index 4c59524796..496c71c936 100644 --- a/node/src/transition_frontier/sync/transition_frontier_sync_effects.rs +++ b/node/src/transition_frontier/sync/transition_frontier_sync_effects.rs @@ -243,17 +243,27 @@ impl TransitionFrontierSyncAction { }; let hash = block.hash.clone(); + // During catchup, we skip the verificationf of completed work and zkApp txn proofs + // until get closer to the best tip, at which point full verification is enabled. + let skip_verification = super::CATCHUP_BLOCK_VERIFY_TAIL_LENGTH + < store.state().transition_frontier.sync.pending_count(); + if let Some(stats) = store.service.stats() { stats.block_producer().block_apply_start(meta.time(), &hash); } store.dispatch(LedgerWriteAction::Init { - request: LedgerWriteRequest::BlockApply { block, pred_block }, + request: LedgerWriteRequest::BlockApply { + block, + pred_block, + skip_verification, + }, on_init: redux::callback!( on_block_next_apply_init(request: LedgerWriteRequest) -> crate::Action { let LedgerWriteRequest::BlockApply { block, pred_block: _, + skip_verification: _, } = request else { unreachable!() diff --git a/node/src/transition_frontier/sync/transition_frontier_sync_state.rs b/node/src/transition_frontier/sync/transition_frontier_sync_state.rs index 7827d24244..848fbd8684 100644 --- a/node/src/transition_frontier/sync/transition_frontier_sync_state.rs +++ b/node/src/transition_frontier/sync/transition_frontier_sync_state.rs @@ -277,6 +277,12 @@ impl TransitionFrontierSyncState { } } + pub fn pending_count(&self) -> usize { + self.blocks_iter() + .filter(|b| !matches!(b, TransitionFrontierSyncBlockState::ApplySuccess { .. })) + .count() + } + pub fn blocks_fetch_retry_iter(&self) -> impl '_ + Iterator { self.blocks_iter().filter_map(|s| s.retry_hash()).cloned() } diff --git a/node/src/transition_frontier/transition_frontier_reducer.rs b/node/src/transition_frontier/transition_frontier_reducer.rs index 8aa5d0fedf..284846ff3e 100644 --- a/node/src/transition_frontier/transition_frontier_reducer.rs +++ b/node/src/transition_frontier/transition_frontier_reducer.rs @@ -1,9 +1,8 @@ -use openmina_core::block::AppliedBlock; - use super::sync::{SyncError, TransitionFrontierSyncState}; use super::{ TransitionFrontierAction, TransitionFrontierActionWithMetaRef, TransitionFrontierState, }; +use openmina_core::block::AppliedBlock; impl TransitionFrontierState { pub fn reducer( diff --git a/node/src/transition_frontier/transition_frontier_state.rs b/node/src/transition_frontier/transition_frontier_state.rs index ba2d40b14b..69811b0c0d 100644 --- a/node/src/transition_frontier/transition_frontier_state.rs +++ b/node/src/transition_frontier/transition_frontier_state.rs @@ -3,6 +3,7 @@ use std::collections::BTreeMap; use ledger::transaction_pool::diff::BestTipDiff; use mina_p2p_messages::v2::{ MinaStateProtocolStateBodyValueStableV2, MinaStateProtocolStateValueStableV2, StateHash, + TransactionHash, }; use openmina_core::block::{AppliedBlock, ArcBlockWithHash}; use serde::{Deserialize, Serialize}; @@ -60,6 +61,17 @@ impl TransitionFrontierState { self.best_chain.first() } + /// FIXME + /// Note(adonagy): This can be expensive, keep a map with all the tx hashis in the best chain + pub fn contains_transaction(&self, hash: &TransactionHash) -> bool { + self.best_chain.iter().any(|block| { + block + .body() + .transactions() + .any(|transaction| transaction.hash().as_ref().ok() == Some(hash)) + }) + } + /// Looks up state body by state hash. pub fn get_state_body( &self, diff --git a/node/testing/Cargo.toml b/node/testing/Cargo.toml index 0200e56145..fe9c1946ff 100644 --- a/node/testing/Cargo.toml +++ b/node/testing/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openmina-node-testing" -version = "0.9.0" +version = "0.10.0" edition = "2021" license = "Apache-2.0" diff --git a/node/testing/src/cluster/mod.rs b/node/testing/src/cluster/mod.rs index c67998b6cc..c2073d856a 100644 --- a/node/testing/src/cluster/mod.rs +++ b/node/testing/src/cluster/mod.rs @@ -273,6 +273,8 @@ impl Cluster { global: GlobalConfig { build: BuildEnv::get().into(), snarker: testing_config.snark_worker, + consensus_constants: consensus_consts.clone(), + testing_run: true, }, p2p: P2pConfig { libp2p_port: Some(libp2p_port), diff --git a/node/testing/src/service/rpc_service.rs b/node/testing/src/service/rpc_service.rs index 8f5a20872b..442e97c135 100644 --- a/node/testing/src/service/rpc_service.rs +++ b/node/testing/src/service/rpc_service.rs @@ -81,6 +81,10 @@ impl RpcService for super::NodeTestingService { respond_transaction_pool, node::rpc::RpcTransactionPoolResponse ); + to_real!( + respond_ledger_slim_accounts, + node::rpc::RpcLedgerSlimAccountsResponse + ); to_real!( respond_ledger_accounts, node::rpc::RpcLedgerAccountsResponse @@ -93,4 +97,13 @@ impl RpcService for super::NodeTestingService { respond_transition_frontier_commands, node::rpc::RpcTransitionFrontierUserCommandsResponse, ); + to_real!(respond_best_chain, node::rpc::RpcBestChainResponse,); + to_real!( + respond_consensus_constants, + node::rpc::RpcConsensusConstantsGetResponse, + ); + to_real!( + respond_transaction_status, + node::rpc::RpcTransactionStatusGetResponse, + ); } diff --git a/node/web/Cargo.toml b/node/web/Cargo.toml index faf6b6a130..9813455cae 100644 --- a/node/web/Cargo.toml +++ b/node/web/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openmina-node-web" -version = "0.9.0" +version = "0.10.0" edition = "2021" license = "Apache-2.0" diff --git a/node/web/src/node/builder.rs b/node/web/src/node/builder.rs index 1d4d2029ba..d272a0027b 100644 --- a/node/web/src/node/builder.rs +++ b/node/web/src/node/builder.rs @@ -211,11 +211,19 @@ impl NodeBuilder { .custom_initial_time .unwrap_or_else(redux::Timestamp::global_now); + let transition_frontier = TransitionFrontierConfig::new(self.genesis_config); + + let protocol_constants = transition_frontier.genesis.protocol_constants()?; + let consensus_consts = + ConsensusConstants::create(constraint_constants(), &protocol_constants); + // build config let node_config = node::Config { global: GlobalConfig { build: node::BuildEnv::get().into(), snarker: self.snarker, + consensus_constants: consensus_consts.clone(), + testing_run: false, }, p2p: P2pConfig { libp2p_port: None, @@ -241,7 +249,7 @@ impl NodeBuilder { work_verifier_index, work_verifier_srs: srs, }, - transition_frontier: TransitionFrontierConfig::new(self.genesis_config), + transition_frontier, block_producer: self.block_producer, tx_pool: ledger::transaction_pool::Config { trust_system: (), @@ -258,13 +266,6 @@ impl NodeBuilder { service.p2p_init(p2p_sec_key, P2pTaskSpawner {}); } - let protocol_constants = node_config - .transition_frontier - .genesis - .protocol_constants()?; - let consensus_consts = - ConsensusConstants::create(constraint_constants(), &protocol_constants); - let service = service.build()?; let state = node::State::new(node_config, &consensus_consts, initial_time); diff --git a/p2p/Cargo.toml b/p2p/Cargo.toml index e55c8583c5..179d8aa67e 100644 --- a/p2p/Cargo.toml +++ b/p2p/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "p2p" -version = "0.9.0" +version = "0.10.0" edition = "2021" license = "Apache-2.0" diff --git a/p2p/libp2p-rpc-behaviour/Cargo.toml b/p2p/libp2p-rpc-behaviour/Cargo.toml index e34c1a64ed..25f2c202b9 100644 --- a/p2p/libp2p-rpc-behaviour/Cargo.toml +++ b/p2p/libp2p-rpc-behaviour/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libp2p-rpc-behaviour" -version = "0.9.0" +version = "0.10.0" edition = "2021" license = "Apache-2.0" diff --git a/p2p/src/channels/best_tip/p2p_channels_best_tip_reducer.rs b/p2p/src/channels/best_tip/p2p_channels_best_tip_reducer.rs index 1bb2af3839..2a64f7797f 100644 --- a/p2p/src/channels/best_tip/p2p_channels_best_tip_reducer.rs +++ b/p2p/src/channels/best_tip/p2p_channels_best_tip_reducer.rs @@ -97,7 +97,7 @@ impl P2pChannelsBestTipState { dispatcher.push(P2pChannelsBestTipAction::RequestSend { peer_id }); Ok(()) } - P2pChannelsBestTipAction::RequestReceived { .. } => { + P2pChannelsBestTipAction::RequestReceived { peer_id, .. } => { let Self::Ready { remote, .. } = best_tip_state else { bug_condition!( "Invalid state for `P2pChannelsBestTipAction::RequestReceived`, state: {:?}", @@ -107,6 +107,16 @@ impl P2pChannelsBestTipState { }; *remote = BestTipPropagationState::Requested { time: meta.time() }; + + let (dispatcher, state) = state_context.into_dispatcher_and_state(); + let p2p_state: &P2pState = state.substate()?; + + if let Some(callback) = &p2p_state + .callbacks + .on_p2p_channels_best_tip_request_received + { + dispatcher.push_callback(callback.clone(), *peer_id); + } Ok(()) } P2pChannelsBestTipAction::ResponseSend { best_tip, .. } => { diff --git a/p2p/src/channels/rpc/p2p_channels_rpc_reducer.rs b/p2p/src/channels/rpc/p2p_channels_rpc_reducer.rs index 74b9a62e41..c0dbd8a156 100644 --- a/p2p/src/channels/rpc/p2p_channels_rpc_reducer.rs +++ b/p2p/src/channels/rpc/p2p_channels_rpc_reducer.rs @@ -58,6 +58,13 @@ impl P2pChannelsRpcState { last_responded: redux::Timestamp::ZERO, }, }; + + let (dispatcher, state) = state_context.into_dispatcher_and_state(); + let p2p_state: &P2pState = state.substate()?; + + if let Some(callback) = &p2p_state.callbacks.on_p2p_channels_rpc_ready { + dispatcher.push_callback(callback.clone(), peer_id); + } Ok(()) } P2pChannelsRpcAction::RequestSend { @@ -108,8 +115,21 @@ impl P2pChannelsRpcState { }); Ok(()) } - P2pChannelsRpcAction::Timeout { .. } => Ok(()), - P2pChannelsRpcAction::ResponseReceived { response, .. } => { + P2pChannelsRpcAction::Timeout { id, .. } => { + let (dispatcher, state) = state_context.into_dispatcher_and_state(); + let p2p_state: &P2pState = state.substate()?; + + if let Some(callback) = &p2p_state.callbacks.on_p2p_channels_rpc_timeout { + dispatcher.push_callback(callback.clone(), (peer_id, *id)); + } + + Ok(()) + } + P2pChannelsRpcAction::ResponseReceived { + response, + id: rpc_id, + .. + } => { let Self::Ready { local, .. } = rpc_state else { bug_condition!( "Invalid state for `P2pChannelsRpcAction::ResponseReceived`, state: {:?}", @@ -130,7 +150,9 @@ impl P2pChannelsRpcState { request: std::mem::take(request), }; - let dispatcher = state_context.into_dispatcher(); + let (dispatcher, state) = state_context.into_dispatcher_and_state(); + let p2p_state: &P2pState = state.substate()?; + if let Some(P2pRpcResponse::BestTipWithProof(resp)) = response.as_deref() { let Ok(best_tip) = BlockWithHash::try_new(resp.best_tip.clone()) else { error!(meta.time(); "P2pChannelsRpcAction::ResponseReceived: Invalid bigint in block"); @@ -139,6 +161,11 @@ impl P2pChannelsRpcState { dispatcher.push(P2pPeerAction::BestTipUpdate { peer_id, best_tip }); } + + if let Some(callback) = &p2p_state.callbacks.on_p2p_channels_rpc_response_received { + dispatcher + .push_callback(callback.clone(), (peer_id, *rpc_id, response.clone())); + } Ok(()) } P2pChannelsRpcAction::RequestReceived { id, request, .. } => { @@ -157,6 +184,13 @@ impl P2pChannelsRpcState { request: (**request).clone(), is_pending: false, }); + + let (dispatcher, state) = state_context.into_dispatcher_and_state(); + let p2p_state: &P2pState = state.substate()?; + + if let Some(callback) = &p2p_state.callbacks.on_p2p_channels_rpc_request_received { + dispatcher.push_callback(callback.clone(), (peer_id, *id, request.clone())); + } Ok(()) } P2pChannelsRpcAction::ResponsePending { id, .. } => { diff --git a/p2p/src/channels/snark/p2p_channels_snark_reducer.rs b/p2p/src/channels/snark/p2p_channels_snark_reducer.rs index e6caf85ac0..c78f8933c2 100644 --- a/p2p/src/channels/snark/p2p_channels_snark_reducer.rs +++ b/p2p/src/channels/snark/p2p_channels_snark_reducer.rs @@ -94,7 +94,7 @@ impl P2pChannelsSnarkState { }; Ok(()) } - P2pChannelsSnarkAction::Received { .. } => { + P2pChannelsSnarkAction::Received { peer_id, snark } => { let state = state.inspect_err(|error| bug_condition!("{}", error))?; let Self::Ready { local, .. } = state else { bug_condition!( @@ -124,6 +124,14 @@ impl P2pChannelsSnarkState { count: *current_count, }; } + + let (dispatcher, state) = state_context.into_dispatcher_and_state(); + let p2p_state: &P2pState = state.substate()?; + + if let Some(callback) = &p2p_state.callbacks.on_p2p_channels_snark_received { + dispatcher.push_callback(callback.clone(), (*peer_id, snark.clone())); + } + Ok(()) } P2pChannelsSnarkAction::RequestReceived { limit, .. } => { @@ -191,7 +199,16 @@ impl P2pChannelsSnarkState { } #[cfg(not(feature = "p2p-libp2p"))] P2pChannelsSnarkAction::Libp2pBroadcast { .. } => Ok(()), - P2pChannelsSnarkAction::Libp2pReceived { .. } => Ok(()), + P2pChannelsSnarkAction::Libp2pReceived { peer_id, snark, .. } => { + let (dispatcher, state) = state_context.into_dispatcher_and_state(); + let p2p_state: &P2pState = state.substate()?; + + if let Some(callback) = &p2p_state.callbacks.on_p2p_channels_snark_libp2p_received { + dispatcher.push_callback(callback.clone(), (*peer_id, snark.clone())); + } + + Ok(()) + } } } } diff --git a/p2p/src/channels/snark_job_commitment/p2p_channels_snark_job_commitment_reducer.rs b/p2p/src/channels/snark_job_commitment/p2p_channels_snark_job_commitment_reducer.rs index 6dfe23ea21..ab1617a134 100644 --- a/p2p/src/channels/snark_job_commitment/p2p_channels_snark_job_commitment_reducer.rs +++ b/p2p/src/channels/snark_job_commitment/p2p_channels_snark_job_commitment_reducer.rs @@ -110,7 +110,7 @@ impl P2pChannelsSnarkJobCommitmentState { }; Ok(()) } - P2pChannelsSnarkJobCommitmentAction::Received { .. } => { + P2pChannelsSnarkJobCommitmentAction::Received { commitment, .. } => { let Self::Ready { local, .. } = snark_job_state else { bug_condition!( "Invalid state for `P2pChannelsSnarkJobCommitmentAction::Received`, state: {:?}", @@ -140,11 +140,19 @@ impl P2pChannelsSnarkJobCommitmentState { }; } - let dispatcher = state_context.into_dispatcher(); + let (dispatcher, state) = state_context.into_dispatcher_and_state(); + let p2p_state: &P2pState = state.substate()?; dispatcher.push(P2pChannelsSnarkJobCommitmentAction::RequestSend { peer_id, limit: LIMIT, }); + + if let Some(callback) = &p2p_state + .callbacks + .on_p2p_channels_snark_job_commitment_received + { + dispatcher.push_callback(callback.clone(), (peer_id, commitment.clone())); + } Ok(()) } P2pChannelsSnarkJobCommitmentAction::RequestReceived { limit, .. } => { diff --git a/p2p/src/channels/streaming_rpc/p2p_channels_streaming_rpc_reducer.rs b/p2p/src/channels/streaming_rpc/p2p_channels_streaming_rpc_reducer.rs index bb069daa49..7b4d425ceb 100644 --- a/p2p/src/channels/streaming_rpc/p2p_channels_streaming_rpc_reducer.rs +++ b/p2p/src/channels/streaming_rpc/p2p_channels_streaming_rpc_reducer.rs @@ -50,6 +50,13 @@ impl P2pChannelsStreamingRpcState { remote: P2pStreamingRpcRemoteState::WaitingForRequest { time: meta.time() }, remote_last_responded: redux::Timestamp::ZERO, }; + + let (dispatcher, state) = state_context.into_dispatcher_and_state(); + let p2p_state: &P2pState = state.substate()?; + + if let Some(callback) = &p2p_state.callbacks.on_p2p_channels_streaming_rpc_ready { + dispatcher.push_callback(callback.clone(), ()); + } Ok(()) } P2pChannelsStreamingRpcAction::RequestSend { @@ -86,7 +93,16 @@ impl P2pChannelsStreamingRpcState { }); Ok(()) } - P2pChannelsStreamingRpcAction::Timeout { .. } => Ok(()), + P2pChannelsStreamingRpcAction::Timeout { id, .. } => { + let (dispatcher, state) = state_context.into_dispatcher_and_state(); + let p2p_state: &P2pState = state.substate()?; + + if let Some(callback) = &p2p_state.callbacks.on_p2p_channels_streaming_rpc_timeout { + dispatcher.push_callback(callback.clone(), (peer_id, *id)); + } + + Ok(()) + } P2pChannelsStreamingRpcAction::ResponseNextPartGet { id, .. } => { let Self::Ready { local: P2pStreamingRpcLocalState::Requested { progress, .. }, @@ -145,7 +161,11 @@ impl P2pChannelsStreamingRpcState { .push(P2pChannelsStreamingRpcAction::ResponseNextPartGet { peer_id, id: *id }); Ok(()) } - P2pChannelsStreamingRpcAction::ResponseReceived { .. } => { + P2pChannelsStreamingRpcAction::ResponseReceived { + id: rpc_id, + response, + .. + } => { let Self::Ready { local, .. } = streaming_rpc_state else { bug_condition!("{:?} with state {:?}", action, streaming_rpc_state); return Ok(()); @@ -159,6 +179,17 @@ impl P2pChannelsStreamingRpcState { id: *id, request: std::mem::take(request), }; + + let (dispatcher, state) = state_context.into_dispatcher_and_state(); + let p2p_state: &P2pState = state.substate()?; + + if let Some(callback) = &p2p_state + .callbacks + .on_p2p_channels_streaming_rpc_response_received + { + dispatcher.push_callback(callback.clone(), (peer_id, *rpc_id, response.clone())) + } + Ok(()) } P2pChannelsStreamingRpcAction::RequestReceived { id, request, .. } => { diff --git a/p2p/src/channels/transaction/p2p_channels_transaction_actions.rs b/p2p/src/channels/transaction/p2p_channels_transaction_actions.rs index 400c6b1091..e4f9851b7b 100644 --- a/p2p/src/channels/transaction/p2p_channels_transaction_actions.rs +++ b/p2p/src/channels/transaction/p2p_channels_transaction_actions.rs @@ -29,6 +29,7 @@ pub enum P2pChannelsTransactionAction { peer_id: PeerId, promised_count: u8, }, + // TODO(binier): propagate tx info received to pool Received { peer_id: PeerId, transaction: Box, diff --git a/p2p/src/channels/transaction/p2p_channels_transaction_reducer.rs b/p2p/src/channels/transaction/p2p_channels_transaction_reducer.rs index 0acc3de62d..5a85bcc568 100644 --- a/p2p/src/channels/transaction/p2p_channels_transaction_reducer.rs +++ b/p2p/src/channels/transaction/p2p_channels_transaction_reducer.rs @@ -180,7 +180,19 @@ impl P2pChannelsTransactionState { }); Ok(()) } - P2pChannelsTransactionAction::Libp2pReceived { .. } => Ok(()), + P2pChannelsTransactionAction::Libp2pReceived { transaction, .. } => { + let (dispatcher, state) = state_context.into_dispatcher_and_state(); + let p2p_state: &P2pState = state.substate()?; + + if let Some(callback) = &p2p_state + .callbacks + .on_p2p_channels_transaction_libp2p_received + { + dispatcher.push_callback(callback.clone(), transaction.clone()); + } + + Ok(()) + } #[cfg(not(feature = "p2p-libp2p"))] P2pChannelsTransactionAction::Libp2pBroadcast { .. } => Ok(()), #[cfg(feature = "p2p-libp2p")] diff --git a/p2p/src/connection/incoming/p2p_connection_incoming_reducer.rs b/p2p/src/connection/incoming/p2p_connection_incoming_reducer.rs index 1bc8489bd0..5eab82f470 100644 --- a/p2p/src/connection/incoming/p2p_connection_incoming_reducer.rs +++ b/p2p/src/connection/incoming/p2p_connection_incoming_reducer.rs @@ -8,7 +8,7 @@ use crate::{ connection::{ incoming::P2pConnectionIncomingError, incoming_effectful::P2pConnectionIncomingEffectfulAction, - outgoing::P2pConnectionOutgoingInitOpts, P2pConnectionState, + outgoing::P2pConnectionOutgoingInitOpts, P2pConnectionResponse, P2pConnectionState, }, disconnection::{P2pDisconnectionAction, P2pDisconnectionReason}, webrtc::{HttpSignalingInfo, SignalingMethod}, @@ -164,12 +164,29 @@ impl P2pConnectionIncomingState { state ); } - state_context.into_dispatcher().push( - P2pConnectionIncomingEffectfulAction::AnswerSend { - peer_id: *peer_id, - answer: answer.clone(), - }, - ); + let (dispatcher, state) = state_context.into_dispatcher_and_state(); + let p2p_state: &P2pState = state.substate()?; + + dispatcher.push(P2pConnectionIncomingEffectfulAction::AnswerSend { + peer_id: *peer_id, + answer: answer.clone(), + }); + + if let Some(rpc_id) = p2p_state.peer_connection_rpc_id(peer_id) { + if let Some(callback) = + &p2p_state.callbacks.on_p2p_connection_incoming_answer_ready + { + dispatcher.push_callback( + callback.clone(), + ( + rpc_id, + *peer_id, + P2pConnectionResponse::Accepted(answer.clone()), + ), + ); + } + } + Ok(()) } P2pConnectionIncomingAction::AnswerSendSuccess { .. } => { @@ -307,6 +324,17 @@ impl P2pConnectionIncomingState { error: error.clone(), rpc_id, }; + + let (dispatcher, state) = state_context.into_dispatcher_and_state(); + let p2p_state: &P2pState = state.substate()?; + + if let Some(rpc_id) = p2p_state.peer_connection_rpc_id(&peer_id) { + if let Some(callback) = &p2p_state.callbacks.on_p2p_connection_incoming_error { + dispatcher + .push_callback(callback.clone(), (rpc_id, format!("{:?}", error))); + } + } + Ok(()) } P2pConnectionIncomingAction::Success { .. } => { @@ -337,11 +365,20 @@ impl P2pConnectionIncomingState { return Ok(()); } - let dispatcher = state_context.into_dispatcher(); + let (dispatcher, state) = state_context.into_dispatcher_and_state(); + let p2p_state: &P2pState = state.substate()?; + dispatcher.push(P2pPeerAction::Ready { peer_id, incoming: true, }); + + if let Some(rpc_id) = p2p_state.peer_connection_rpc_id(&peer_id) { + if let Some(callback) = &p2p_state.callbacks.on_p2p_connection_incoming_success + { + dispatcher.push_callback(callback.clone(), rpc_id); + } + } Ok(()) } P2pConnectionIncomingAction::FinalizePendingLibp2p { addr, .. } => { diff --git a/p2p/src/connection/outgoing/p2p_connection_outgoing_reducer.rs b/p2p/src/connection/outgoing/p2p_connection_outgoing_reducer.rs index 157a3d0a3f..6da92bf33b 100644 --- a/p2p/src/connection/outgoing/p2p_connection_outgoing_reducer.rs +++ b/p2p/src/connection/outgoing/p2p_connection_outgoing_reducer.rs @@ -417,11 +417,11 @@ impl P2pConnectionOutgoingState { rpc_id, }; + let (dispatcher, state) = state_context.into_dispatcher_and_state(); + let p2p_state: &P2pState = state.substate()?; + #[cfg(feature = "p2p-libp2p")] { - let (dispatcher, state) = state_context.into_dispatcher_and_state(); - let p2p_state: &P2pState = state.substate()?; - if p2p_state .network .scheduler @@ -435,6 +435,12 @@ impl P2pConnectionOutgoingState { }); } } + + if let Some(rpc_id) = p2p_state.peer_connection_rpc_id(peer_id) { + if let Some(callback) = &p2p_state.callbacks.on_p2p_connection_outgoing_error { + dispatcher.push_callback(callback.clone(), (rpc_id, error.clone())); + } + } Ok(()) } P2pConnectionOutgoingAction::Success { peer_id } => { @@ -463,11 +469,19 @@ impl P2pConnectionOutgoingState { return Ok(()); } - let dispatcher = state_context.into_dispatcher(); + let (dispatcher, state) = state_context.into_dispatcher_and_state(); + let p2p_state: &P2pState = state.substate()?; dispatcher.push(P2pPeerAction::Ready { peer_id: *peer_id, incoming: false, }); + + if let Some(rpc_id) = p2p_state.peer_connection_rpc_id(peer_id) { + if let Some(callback) = &p2p_state.callbacks.on_p2p_connection_outgoing_success + { + dispatcher.push_callback(callback.clone(), rpc_id); + } + } Ok(()) } } diff --git a/p2p/src/disconnection/p2p_disconnection_reducer.rs b/p2p/src/disconnection/p2p_disconnection_reducer.rs index 630594a978..673327019b 100644 --- a/p2p/src/disconnection/p2p_disconnection_reducer.rs +++ b/p2p/src/disconnection/p2p_disconnection_reducer.rs @@ -59,8 +59,13 @@ impl P2pDisconnectedState { }; peer.status = P2pPeerStatus::Disconnected { time: meta.time() }; - let dispatcher = state_context.into_dispatcher(); + let (dispatcher, state) = state_context.into_dispatcher_and_state(); + let p2p_state: &P2pState = state.substate()?; dispatcher.push(P2pPeerAction::Remove { peer_id: *peer_id }); + + if let Some(callback) = &p2p_state.callbacks.on_p2p_disconnection_finish { + dispatcher.push_callback(callback.clone(), *peer_id); + } Ok(()) } #[cfg(feature = "p2p-libp2p")] @@ -83,8 +88,14 @@ impl P2pDisconnectedState { }; peer.status = P2pPeerStatus::Disconnected { time: meta.time() }; - let dispatcher = state_context.into_dispatcher(); + let (dispatcher, state) = state_context.into_dispatcher_and_state(); + let p2p_state: &P2pState = state.substate()?; dispatcher.push(P2pPeerAction::Remove { peer_id: *peer_id }); + + if let Some(callback) = &p2p_state.callbacks.on_p2p_disconnection_finish { + dispatcher.push_callback(callback.clone(), *peer_id); + } + Ok(()) } } diff --git a/p2p/src/network/yamux/p2p_network_yamux_reducer.rs b/p2p/src/network/yamux/p2p_network_yamux_reducer.rs index 5899a9f102..fad0dedd58 100644 --- a/p2p/src/network/yamux/p2p_network_yamux_reducer.rs +++ b/p2p/src/network/yamux/p2p_network_yamux_reducer.rs @@ -208,7 +208,8 @@ impl P2pNetworkYamuxState { if let Some(stream) = yamux_state.streams.get_mut(&frame.stream_id) { // must not underflow // TODO: check it and disconnect peer that violates flow rules - stream.window_ours -= data.len() as u32; + stream.window_ours = + stream.window_ours.wrapping_sub(data.len() as u32); } } YamuxFrameInner::WindowUpdate { difference } => { @@ -334,7 +335,7 @@ impl P2pNetworkYamuxState { // must not underflow // the action must not dispatch if it doesn't fit in the window // TODO: add pending queue, where frames will wait for window increase - stream.window_theirs -= data.len() as u32; + stream.window_theirs = stream.window_theirs.wrapping_sub(data.len() as u32); } YamuxFrameInner::WindowUpdate { difference } => { stream.update_window(true, *difference); @@ -417,11 +418,11 @@ impl YamuxStreamState { if *window < decreasing { *window = 0; } else { - *window -= decreasing; + *window = (*window).wrapping_sub(decreasing); } } else { let increasing = difference as u32; - *window += increasing; + *window = (*window).wrapping_add(increasing); } } } diff --git a/p2p/src/p2p_effects.rs b/p2p/src/p2p_effects.rs index 506387ab03..dad83e8c6d 100644 --- a/p2p/src/p2p_effects.rs +++ b/p2p/src/p2p_effects.rs @@ -1,274 +1,8 @@ -use openmina_core::bug_condition; -use redux::{ActionMeta, ActionWithMeta}; - -use crate::{ - channels::P2pChannelsEffectfulAction, - connection::{outgoing::P2pConnectionOutgoingAction, P2pConnectionEffectfulAction}, - P2pAction, P2pStore, -}; -#[cfg(feature = "p2p-libp2p")] use crate::{ - P2pNetworkKadKey, P2pNetworkKademliaAction, P2pNetworkPnetAction, P2pNetworkSelectAction, - PeerId, + channels::P2pChannelsEffectfulAction, connection::P2pConnectionEffectfulAction, P2pAction, + P2pStore, }; - -pub fn p2p_timeout_effects(store: &mut Store, meta: &ActionMeta) -where - Store: P2pStore, -{ - p2p_connection_timeouts(store, meta); - store.dispatch(P2pConnectionOutgoingAction::RandomInit); - - p2p_try_reconnect_disconnected_peers(store, meta.time()); - - #[cfg(feature = "p2p-libp2p")] - p2p_pnet_timeouts(store, meta); - - p2p_discovery(store, meta); - - #[cfg(feature = "p2p-libp2p")] - p2p_select_timeouts(store, meta); - #[cfg(feature = "p2p-libp2p")] - p2p_rpc_heartbeats(store, meta); - - let state = store.state(); - for (peer_id, id, is_streaming) in state.peer_rpc_timeouts(meta.time()) { - if !is_streaming { - store.dispatch(crate::channels::rpc::P2pChannelsRpcAction::Timeout { peer_id, id }); - } else { - store.dispatch( - crate::channels::streaming_rpc::P2pChannelsStreamingRpcAction::Timeout { - peer_id, - id, - }, - ); - } - } -} - -#[cfg(feature = "p2p-libp2p")] -fn p2p_pnet_timeouts(store: &mut Store, meta: &ActionMeta) -where - Store: P2pStore, -{ - let now = meta.time(); - let timeouts = &store.state().config.timeouts; - let pnet_timeouts: Vec<_> = store - .state() - .network - .scheduler - .connections - .iter() - .filter_map(|(sock_addr, state)| { - if state.pnet.is_timed_out(now, timeouts) { - Some(*sock_addr) - } else { - None - } - }) - .collect(); - - for addr in pnet_timeouts { - store.dispatch(P2pNetworkPnetAction::Timeout { addr }); - } -} - -#[cfg(feature = "p2p-libp2p")] -fn p2p_select_timeouts(store: &mut Store, meta: &ActionMeta) -where - Store: P2pStore, -{ - let now = meta.time(); - let timeouts = &store.state().config.timeouts; - let select_auth_timeouts: Vec<_> = store - .state() - .network - .scheduler - .connections - .iter() - .filter_map(|(sock_addr, state)| { - if state.select_auth.is_timed_out(now, timeouts) { - Some(*sock_addr) - } else { - None - } - }) - .collect(); - - let select_mux_timeouts: Vec<_> = store - .state() - .network - .scheduler - .connections - .iter() - .filter_map(|(sock_addr, state)| { - if state.select_mux.is_timed_out(now, timeouts) { - Some(*sock_addr) - } else { - None - } - }) - .collect(); - - let select_stream_timeouts: Vec<_> = store - .state() - .network - .scheduler - .connections - .iter() - .flat_map(|(sock_addr, state)| { - state.streams.iter().filter_map(|(stream_id, stream)| { - if stream.select.is_timed_out(now, timeouts) { - Some((*sock_addr, *stream_id)) - } else { - None - } - }) - }) - .collect(); - - for addr in select_auth_timeouts { - store.dispatch(P2pNetworkSelectAction::Timeout { - addr, - kind: crate::SelectKind::Authentication, - }); - } - - for addr in select_mux_timeouts { - store.dispatch(P2pNetworkSelectAction::Timeout { - addr, - kind: crate::SelectKind::MultiplexingNoPeerId, - }); - } - - for (addr, stream_id) in select_stream_timeouts { - // TODO: better solution for PeerId - let dummy = PeerId::from_bytes([0u8; 32]); - - store.dispatch(P2pNetworkSelectAction::Timeout { - addr, - kind: crate::SelectKind::Stream(dummy, stream_id), - }); - } -} - -#[cfg(feature = "p2p-libp2p")] -fn p2p_rpc_heartbeats(store: &mut Store, meta: &ActionMeta) -where - Store: P2pStore, -{ - use crate::network::rpc::P2pNetworkRpcAction; - let scheduler = &store.state().network.scheduler; - - let send_heartbeat_actions: Vec<_> = scheduler - .rpc_incoming_streams - .iter() - .chain(&scheduler.rpc_outgoing_streams) - .flat_map(|(peer_id, state)| { - state - .iter() - .filter(|(_, s)| s.should_send_heartbeat(meta.time())) - .map(|(stream_id, state)| P2pNetworkRpcAction::HeartbeatSend { - addr: state.addr, - peer_id: *peer_id, - stream_id: *stream_id, - }) - }) - .collect(); - for action in send_heartbeat_actions { - store.dispatch(action); - } -} - -fn p2p_connection_timeouts(store: &mut Store, meta: &ActionMeta) -where - Store: P2pStore, -{ - use crate::connection::incoming::P2pConnectionIncomingAction; - - let now = meta.time(); - let timeouts = &store.state().config.timeouts; - let p2p_connection_timeouts: Vec<_> = store - .state() - .peers - .iter() - .filter_map(|(peer_id, peer)| { - let s = peer.status.as_connecting()?; - match s.is_timed_out(now, timeouts) { - true => Some((*peer_id, s.as_outgoing().is_some())), - false => None, - } - }) - .collect(); - - for (peer_id, is_outgoing) in p2p_connection_timeouts { - match is_outgoing { - true => store.dispatch(P2pConnectionOutgoingAction::Timeout { peer_id }), - false => store.dispatch(P2pConnectionIncomingAction::Timeout { peer_id }), - }; - } -} - -fn p2p_try_reconnect_disconnected_peers(store: &mut Store, now: redux::Timestamp) -where - Store: P2pStore, -{ - if store.state().already_has_min_peers() { - return; - } - let timeouts = &store.state().config.timeouts; - let reconnect_actions: Vec<_> = store - .state() - .peers - .iter() - .filter_map(|(_, p)| { - if p.can_reconnect(now, timeouts) { - p.dial_opts.clone() - } else { - None - } - }) - .map(|opts| P2pConnectionOutgoingAction::Reconnect { opts, rpc_id: None }) - .collect(); - for action in reconnect_actions { - store.dispatch(action); - } -} - -fn p2p_discovery(store: &mut Store, meta: &redux::ActionMeta) -where - Store: P2pStore, -{ - let now = meta.time(); - let state = store.state(); - let config = &state.config; - if !config.peer_discovery { - return; - } - // ask initial peers - if let Some(_d) = config.timeouts.initial_peers { - // TODO: use RPC to ask initial peers - let _ = now; - } - - #[cfg(feature = "p2p-libp2p")] - if let Some(discovery_state) = state.network.scheduler.discovery_state() { - let my_id = state.my_id(); - match P2pNetworkKadKey::try_from(&my_id) { - Ok(key) => { - if discovery_state - .routing_table - .closest_peers(&key) - .any(|_| true) - && discovery_state.status.can_bootstrap(now, &config.timeouts) - { - store.dispatch(P2pNetworkKademliaAction::StartBootstrap { key: my_id }); - } - } - Err(e) => bug_condition!("p2p_discovery error {:?}", e), - } - } -} +use redux::ActionWithMeta; pub fn p2p_effects(store: &mut Store, action: ActionWithMeta) where diff --git a/p2p/src/p2p_reducer.rs b/p2p/src/p2p_reducer.rs index 6d7f5fc29a..7261a220fa 100644 --- a/p2p/src/p2p_reducer.rs +++ b/p2p/src/p2p_reducer.rs @@ -1,9 +1,18 @@ use crate::{ - channels::P2pChannelsState, connection::P2pConnectionState, - disconnection::P2pDisconnectedState, P2pAction, P2pActionWithMetaRef, P2pNetworkState, - P2pPeerState, P2pState, + channels::{ + rpc::P2pChannelsRpcAction, streaming_rpc::P2pChannelsStreamingRpcAction, P2pChannelsState, + }, + connection::{ + incoming::P2pConnectionIncomingAction, outgoing::P2pConnectionOutgoingAction, + P2pConnectionState, + }, + disconnection::P2pDisconnectedState, + P2pAction, P2pActionWithMetaRef, P2pNetworkKadKey, P2pNetworkKademliaAction, + P2pNetworkPnetAction, P2pNetworkRpcAction, P2pNetworkSelectAction, P2pNetworkState, + P2pPeerState, P2pState, PeerId, }; use openmina_core::{bug_condition, Substate}; +use redux::{ActionMeta, Dispatcher, Timestamp}; impl P2pState { pub fn reducer( @@ -63,4 +72,267 @@ impl P2pState { } } } + + pub fn p2p_timeout_dispatch( + state_context: Substate, + meta: &ActionMeta, + ) -> Result<(), String> + where + State: crate::P2pStateTrait, + Action: crate::P2pActionTrait, + { + let (dispatcher, state) = state_context.into_dispatcher_and_state(); + let state: &P2pState = state.substate()?; + let time = meta.time(); + + state.p2p_connection_timeouts_dispatch(dispatcher, time)?; + dispatcher.push(P2pConnectionOutgoingAction::RandomInit); + + state.p2p_try_reconnect_disconnected_peers(dispatcher, time)?; + state.p2p_discovery(dispatcher, time)?; + + #[cfg(feature = "p2p-libp2p")] + { + state.p2p_pnet_timeouts(dispatcher, time)?; + state.p2p_select_timeouts(dispatcher, time)?; + state.p2p_rpc_heartbeats(dispatcher, time)?; + } + + state.rpc_timeouts(dispatcher, time)?; + Ok(()) + } + + fn p2p_connection_timeouts_dispatch( + &self, + dispatcher: &mut Dispatcher, + time: Timestamp, + ) -> Result<(), String> + where + State: crate::P2pStateTrait, + Action: crate::P2pActionTrait, + { + let timeouts = &self.config.timeouts; + + self.peers + .iter() + .filter_map(|(peer_id, peer)| { + let state = peer.status.as_connecting()?; + state + .is_timed_out(time, timeouts) + .then(|| (*peer_id, state.as_outgoing().is_some())) + }) + .for_each(|(peer_id, is_outgoing)| match is_outgoing { + true => dispatcher.push(P2pConnectionOutgoingAction::Timeout { peer_id }), + false => dispatcher.push(P2pConnectionIncomingAction::Timeout { peer_id }), + }); + + Ok(()) + } + + fn p2p_try_reconnect_disconnected_peers( + &self, + dispatcher: &mut Dispatcher, + time: Timestamp, + ) -> Result<(), String> + where + State: crate::P2pStateTrait, + Action: crate::P2pActionTrait, + { + if self.already_has_min_peers() { + return Ok(()); + } + + let timeouts = &self.config.timeouts; + + self.peers + .iter() + .filter_map(|(_, peer)| { + if peer.can_reconnect(time, timeouts) { + peer.dial_opts.clone() + } else { + None + } + }) + .map(|opts| P2pConnectionOutgoingAction::Reconnect { opts, rpc_id: None }) + .for_each(|action| dispatcher.push(action)); + Ok(()) + } + + fn rpc_timeouts( + &self, + dispatcher: &mut Dispatcher, + time: Timestamp, + ) -> Result<(), String> + where + State: crate::P2pStateTrait, + Action: crate::P2pActionTrait, + { + self.peer_rpc_timeouts(time) + .into_iter() + .for_each(|(peer_id, id, is_streaming)| { + if is_streaming { + dispatcher.push(P2pChannelsStreamingRpcAction::Timeout { peer_id, id }); + } else { + dispatcher.push(P2pChannelsRpcAction::Timeout { peer_id, id }); + } + }); + + Ok(()) + } + + fn p2p_discovery( + &self, + dispatcher: &mut Dispatcher, + time: Timestamp, + ) -> Result<(), String> + where + State: crate::P2pStateTrait, + Action: crate::P2pActionTrait, + { + let config = &self.config; + let timeouts = &config.timeouts; + + if !config.peer_discovery { + return Ok(()); + } + + if let Some(_d) = config.timeouts.initial_peers { + // ask initial peers + // TODO: use RPC to ask initial peers + } + + #[cfg(feature = "p2p-libp2p")] + { + if let Some(discovery_state) = self.network.scheduler.discovery_state() { + let my_id = self.my_id(); + + match P2pNetworkKadKey::try_from(&my_id) { + Ok(key) => { + if discovery_state.status.can_bootstrap(time, timeouts) + && discovery_state + .routing_table + .closest_peers(&key) + .any(|_| true) + { + dispatcher + .push(P2pNetworkKademliaAction::StartBootstrap { key: my_id }); + } + } + Err(e) => bug_condition!("p2p discovery error: {:?}", e), + } + } + } + + Ok(()) + } +} + +#[cfg(feature = "p2p-libp2p")] +impl P2pState { + fn p2p_pnet_timeouts( + &self, + dispatcher: &mut Dispatcher, + time: Timestamp, + ) -> Result<(), String> + where + State: crate::P2pStateTrait, + Action: crate::P2pActionTrait, + { + let timeouts = &self.config.timeouts; + + self.network + .scheduler + .connections + .iter() + .filter(|(_, state)| state.pnet.is_timed_out(time, timeouts)) + .map(|(addr, _)| P2pNetworkPnetAction::Timeout { addr: *addr }) + .for_each(|action| dispatcher.push(action)); + + Ok(()) + } + + fn p2p_select_timeouts( + &self, + dispatcher: &mut Dispatcher, + time: Timestamp, + ) -> Result<(), String> + where + State: crate::P2pStateTrait, + Action: crate::P2pActionTrait, + { + let timeouts = &self.config.timeouts; + + self.network + .scheduler + .connections + .iter() + .filter(|(_, state)| state.select_auth.is_timed_out(time, timeouts)) + .map(|(addr, _)| P2pNetworkSelectAction::Timeout { + addr: *addr, + kind: crate::SelectKind::Authentication, + }) + .for_each(|action| dispatcher.push(action)); + + self.network + .scheduler + .connections + .iter() + .filter(|(_, state)| state.select_mux.is_timed_out(time, timeouts)) + .map(|(addr, _)| P2pNetworkSelectAction::Timeout { + addr: *addr, + kind: crate::SelectKind::MultiplexingNoPeerId, + }) + .for_each(|action| dispatcher.push(action)); + + // TODO: better solution for PeerId + let dummy = PeerId::from_bytes([0u8; 32]); + self.network + .scheduler + .connections + .iter() + .flat_map(|(sock_addr, state)| { + state + .streams + .iter() + .filter(|(_, stream)| stream.select.is_timed_out(time, timeouts)) + .map(|(stream_id, _)| (*sock_addr, *stream_id)) + }) + .map(|(addr, stream_id)| P2pNetworkSelectAction::Timeout { + addr, + kind: crate::SelectKind::Stream(dummy, stream_id), + }) + .for_each(|action| dispatcher.push(action)); + + Ok(()) + } + + fn p2p_rpc_heartbeats( + &self, + dispatcher: &mut Dispatcher, + time: Timestamp, + ) -> Result<(), String> + where + State: crate::P2pStateTrait, + Action: crate::P2pActionTrait, + { + let scheduler = &self.network.scheduler; + + scheduler + .rpc_incoming_streams + .iter() + .chain(&scheduler.rpc_outgoing_streams) + .flat_map(|(peer_id, state)| { + state + .iter() + .filter(|(_, s)| s.should_send_heartbeat(time)) + .map(|(stream_id, state)| P2pNetworkRpcAction::HeartbeatSend { + addr: state.addr, + peer_id: *peer_id, + stream_id: *stream_id, + }) + }) + .for_each(|action| dispatcher.push(action)); + + Ok(()) + } } diff --git a/p2p/src/p2p_state.rs b/p2p/src/p2p_state.rs index 6453dce40a..e03d4b1906 100644 --- a/p2p/src/p2p_state.rs +++ b/p2p/src/p2p_state.rs @@ -1,26 +1,40 @@ -use openmina_core::{block::ArcBlockWithHash, ChainId}; -use openmina_core::{impl_substate_access, SubstateAccess}; -use redux::Timestamp; +use openmina_core::{ + block::{ArcBlockWithHash, BlockWithHash}, + impl_substate_access, + requests::RpcId, + snark::{Snark, SnarkInfo, SnarkJobCommitment}, + ChainId, SubstateAccess, +}; +use redux::{Callback, Timestamp}; use serde::{Deserialize, Serialize}; -use std::collections::{BTreeMap, BTreeSet}; - -use openmina_core::requests::RpcId; - -use crate::bootstrap::P2pNetworkKadBootstrapState; -use crate::channels::rpc::P2pRpcId; -use crate::channels::streaming_rpc::P2pStreamingRpcId; -use crate::channels::{ChannelId, P2pChannelsState}; -use crate::connection::incoming::P2pConnectionIncomingState; -use crate::connection::outgoing::{P2pConnectionOutgoingInitOpts, P2pConnectionOutgoingState}; -use crate::network::identify::{P2pNetworkIdentify, P2pNetworkIdentifyState}; -use crate::network::P2pNetworkState; +use std::{ + collections::{BTreeMap, BTreeSet}, + sync::Arc, +}; + use crate::{ - is_time_passed, Limit, P2pLimits, P2pNetworkKadState, P2pNetworkPubsubState, + bootstrap::P2pNetworkKadBootstrapState, + channels::{ + rpc::{P2pRpcId, P2pRpcRequest, P2pRpcResponse}, + streaming_rpc::{P2pStreamingRpcId, P2pStreamingRpcResponseFull}, + ChannelId, P2pChannelsState, + }, + connection::{ + incoming::P2pConnectionIncomingState, + outgoing::{ + P2pConnectionOutgoingError, P2pConnectionOutgoingInitOpts, P2pConnectionOutgoingState, + }, + P2pConnectionResponse, P2pConnectionState, + }, + is_time_passed, + network::{ + identify::{P2pNetworkIdentify, P2pNetworkIdentifyState}, + P2pNetworkState, + }, + Limit, P2pConfig, P2pLimits, P2pNetworkKadState, P2pNetworkPubsubState, P2pNetworkSchedulerState, P2pTimeouts, PeerId, }; - -use super::connection::P2pConnectionState; -use super::P2pConfig; +use mina_p2p_messages::v2::{MinaBaseUserCommandStableV2, MinaBlockBlockStableV2}; #[derive(Serialize, Deserialize, Debug, Clone)] pub struct P2pState { @@ -28,10 +42,11 @@ pub struct P2pState { pub config: P2pConfig, pub network: P2pNetworkState, pub peers: BTreeMap, + pub callbacks: P2pCallbacks, } impl P2pState { - pub fn new(config: P2pConfig, chain_id: &ChainId) -> Self { + pub fn new(config: P2pConfig, callbacks: P2pCallbacks, chain_id: &ChainId) -> Self { let addrs = if cfg!(feature = "p2p-libp2p") { config .libp2p_port @@ -104,6 +119,7 @@ impl P2pState { config, network, peers, + callbacks, } } @@ -471,6 +487,66 @@ impl SubstateAccess for P2pState { } } +type OptionalCallback = Option>; + +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct P2pCallbacks { + /// Callback for [`P2pChannelsTransactionAction::Libp2pReceived`] + pub on_p2p_channels_transaction_libp2p_received: + OptionalCallback>, + /// Callback for [`P2pChannelsSnarkJobCommitmentAction::Received`] + pub on_p2p_channels_snark_job_commitment_received: + OptionalCallback<(PeerId, Box)>, + + /// Callback for [`P2pChannelsSnarkAction::Received`] + pub on_p2p_channels_snark_received: OptionalCallback<(PeerId, Box)>, + /// Callback for [`P2pChannelsSnarkAction::Libp2pReceived`] + pub on_p2p_channels_snark_libp2p_received: OptionalCallback<(PeerId, Box)>, + + /// Callback for [`P2pChannelsBestTipAction::RequestReceived`] + pub on_p2p_channels_best_tip_request_received: OptionalCallback, + + /// Callback for [`P2pDisconnectionAction::Finish`] + pub on_p2p_disconnection_finish: OptionalCallback, + + /// TODO: these 2 should be set by `P2pConnectionOutgoingAction::Init` + /// Callback for [`P2pConnectionOutgoingAction::Error`] + pub on_p2p_connection_outgoing_error: OptionalCallback<(RpcId, P2pConnectionOutgoingError)>, + /// Callback for [`P2pConnectionOutgoingAction::Success`] + pub on_p2p_connection_outgoing_success: OptionalCallback, + + /// TODO: these 3 should be set by `P2pConnectionIncomingAction::Init` + /// Callback for [`P2pConnectionIncomingAction::Error`] + pub on_p2p_connection_incoming_error: OptionalCallback<(RpcId, String)>, + /// Callback for [`P2pConnectionIncomingAction::Success`] + pub on_p2p_connection_incoming_success: OptionalCallback, + /// Callback for [`P2pConnectionIncomingAction::AnswerReady`] + pub on_p2p_connection_incoming_answer_ready: + OptionalCallback<(RpcId, PeerId, P2pConnectionResponse)>, + + /// Callback for [`P2pPeerAction::BestTipUpdate`] + pub on_p2p_peer_best_tip_update: OptionalCallback>>, + + /// Callback for [`P2pChannelsRpcAction::Ready`] + pub on_p2p_channels_rpc_ready: OptionalCallback, + /// Callback for [`P2pChannelsRpcAction::Timeout`] + pub on_p2p_channels_rpc_timeout: OptionalCallback<(PeerId, P2pRpcId)>, + /// Callback for [`P2pChannelsRpcAction::ResponseReceived`] + pub on_p2p_channels_rpc_response_received: + OptionalCallback<(PeerId, P2pRpcId, Option>)>, + /// Callback for [`P2pChannelsRpcAction::RequestReceived`] + pub on_p2p_channels_rpc_request_received: + OptionalCallback<(PeerId, P2pRpcId, Box)>, + + /// Callback for [`P2pChannelsStreamingRpcAction::Ready`] + pub on_p2p_channels_streaming_rpc_ready: OptionalCallback<()>, + /// Callback for [`P2pChannelsStreamingRpcAction::Timeout`] + pub on_p2p_channels_streaming_rpc_timeout: OptionalCallback<(PeerId, P2pRpcId)>, + /// Callback for [`P2pChannelsStreamingRpcAction::ResponseReceived`] + pub on_p2p_channels_streaming_rpc_response_received: + OptionalCallback<(PeerId, P2pRpcId, Option)>, +} + impl_substate_access!(P2pState, P2pNetworkState, network); impl_substate_access!(P2pState, P2pNetworkSchedulerState, network.scheduler); impl_substate_access!(P2pState, P2pLimits, config.limits); diff --git a/p2p/src/peer/p2p_peer_reducer.rs b/p2p/src/peer/p2p_peer_reducer.rs index 1f4705dc96..23f5a532dc 100644 --- a/p2p/src/peer/p2p_peer_reducer.rs +++ b/p2p/src/peer/p2p_peer_reducer.rs @@ -63,6 +63,12 @@ impl P2pPeerState { }; peer.best_tip = Some(best_tip.clone()); + let (dispatcher, state) = state_context.into_dispatcher_and_state(); + let p2p_state: &P2pState = state.substate()?; + + if let Some(callback) = &p2p_state.callbacks.on_p2p_peer_best_tip_update { + dispatcher.push_callback(callback.clone(), best_tip.clone()); + } Ok(()) } P2pPeerAction::Remove { peer_id } => { diff --git a/p2p/testing/Cargo.toml b/p2p/testing/Cargo.toml index 9ac03ff8cf..399ca02e69 100644 --- a/p2p/testing/Cargo.toml +++ b/p2p/testing/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "p2p-testing" -version = "0.9.0" +version = "0.10.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/p2p/testing/src/cluster.rs b/p2p/testing/src/cluster.rs index 4262c0bd61..76544d6a56 100644 --- a/p2p/testing/src/cluster.rs +++ b/p2p/testing/src/cluster.rs @@ -15,7 +15,7 @@ use p2p::{ P2pConnectionOutgoingInitOpts, P2pConnectionOutgoingInitOptsParseError, }, identity::SecretKey, - p2p_effects, p2p_timeout_effects, P2pConfig, P2pMeshsubConfig, P2pState, PeerId, + p2p_effects, P2pCallbacks, P2pConfig, P2pMeshsubConfig, P2pState, PeerId, }; use redux::SystemTime; use tokio::sync::mpsc; @@ -382,17 +382,22 @@ impl Cluster { let store = crate::redux::Store::new( |state, action, dispatcher| { - log_action(action.action(), action.meta(), state.0.my_id()); - if let Action::P2p(p2p_action) = action.action() { - let time = action.meta().time(); - let result = P2pState::reducer( - Substate::new(state, dispatcher), - action.meta().clone().with_action(p2p_action), - ); - - if let Err(error) = result { - openmina_core::warn!(time; "error = {error}"); + let meta = action.meta().clone(); + let action = action.action(); + + log_action(action, &meta, state.0.my_id()); + + let time = meta.time(); + let state_context = Substate::new(state, dispatcher); + let result = match action { + Action::P2p(action) => { + P2pState::reducer(state_context, meta.with_action(action)) } + Action::Idle(_) => P2pState::p2p_timeout_dispatch(state_context, &meta), + }; + + if let Err(error) = result { + openmina_core::warn!(time; "error = {error}"); } }, override_fn.unwrap_or(|store, action| { @@ -402,12 +407,18 @@ impl Cluster { p2p_effects(store, meta.with_action(a.clone())); event_mapper_effect(store, a); } - Action::Idle(_) => p2p_timeout_effects(store, &meta), + Action::Idle(_) => { + // handled by reducer + } } }), service, SystemTime::now(), - State(P2pState::new(config, &self.chain_id)), + State(P2pState::new( + config, + P2pCallbacks::default(), + &self.chain_id, + )), ); let node_id = RustNodeId(self.rust_nodes.len()); diff --git a/p2p/testing/src/redux.rs b/p2p/testing/src/redux.rs index f25afa80f8..f4e9e7d315 100644 --- a/p2p/testing/src/redux.rs +++ b/p2p/testing/src/redux.rs @@ -172,6 +172,10 @@ impl EventContext for ActionLoggerContext { fn node_id(&self) -> &'_ dyn Value { &self.node_id } + + fn log_node_id(&self) -> bool { + true + } } pub(super) fn log_action(action: &Action, meta: &ActionMeta, node_id: PeerId) { diff --git a/p2p/tests/identify.rs b/p2p/tests/identify.rs index a3f9166c84..381cbdb134 100644 --- a/p2p/tests/identify.rs +++ b/p2p/tests/identify.rs @@ -10,7 +10,7 @@ use p2p::{ stream::P2pNetworkIdentifyStreamState, P2pNetworkIdentify, P2pNetworkIdentifyAction, P2pNetworkIdentifyStreamAction, }, - p2p_effects, p2p_timeout_effects, + p2p_effects, token::{self, DiscoveryAlgorithm}, Data, P2pAction, P2pNetworkAction, P2pNetworkYamuxAction, PeerId, }; @@ -268,7 +268,7 @@ fn bad_node_effects( event_mapper_effect(store, a); } Action::Idle(_) => { - p2p_timeout_effects(store, &meta); + // p2p_timeout_effects(store, &meta); } }; } diff --git a/p2p/tests/kademlia.rs b/p2p/tests/kademlia.rs index 8fc39a082a..c126ff705e 100644 --- a/p2p/tests/kademlia.rs +++ b/p2p/tests/kademlia.rs @@ -1,6 +1,6 @@ use p2p::{ - identity::SecretKey, p2p_effects, p2p_timeout_effects, P2pAction, P2pNetworkAction, - P2pNetworkKadAction, P2pNetworkKadBucket, P2pNetworkKademliaAction, P2pNetworkKademliaRpcReply, + identity::SecretKey, p2p_effects, P2pAction, P2pNetworkAction, P2pNetworkKadAction, + P2pNetworkKadBucket, P2pNetworkKademliaAction, P2pNetworkKademliaRpcReply, P2pNetworkKademliaStreamAction, PeerId, }; use p2p_testing::{ @@ -402,7 +402,7 @@ fn bad_node_effects( event_mapper_effect(store, a); } Action::Idle(_) => { - p2p_timeout_effects(store, &meta); + // p2p_timeout_effects(store, &meta); } }; } diff --git a/producer-dashboard/Cargo.toml b/producer-dashboard/Cargo.toml index 4a538f9c89..7ceaf952e2 100644 --- a/producer-dashboard/Cargo.toml +++ b/producer-dashboard/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openmina-producer-dashboard" -version = "0.9.0" +version = "0.10.0" edition = "2021" license = "Apache-2.0" diff --git a/snark/Cargo.toml b/snark/Cargo.toml index c20b8476a3..800ef7fda9 100644 --- a/snark/Cargo.toml +++ b/snark/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "snark" -version = "0.9.0" +version = "0.10.0" edition = "2021" license = "Apache-2.0" diff --git a/tests/files/zkapps/proof_string.txt b/tests/files/zkapps/proof_string.txt new file mode 100644 index 0000000000..7b351fa6cd --- /dev/null +++ b/tests/files/zkapps/proof_string.txt @@ -0,0 +1 @@ +KChzdGF0ZW1lbnQoKHByb29mX3N0YXRlKChkZWZlcnJlZF92YWx1ZXMoKHBsb25rKChhbHBoYSgoaW5uZXIoNGYxNTBjNmU5MGNmZmNlNCBkY2NkNGI4MjhiYjM3ZjgyKSkpKShiZXRhKDNhYzc5YTNiYjVmMThjZjIgMDA3OWM5ZWE4MWQ2MTY5MikpKGdhbW1hKDNjY2ZmMDZkNTM4OWQ4OTEgODc0ZWRiOTJlNGUxNGJlMikpKHpldGEoKGlubmVyKDJiNWI1NThlNzBhYzAxYTcgNGJkMzQ5Yjc0ZDAzOGU1YikpKSkoam9pbnRfY29tYmluZXIoKChpbm5lcigwMDAwMDAwMDAwMDAwMDAwIDAwMDAwMDAwMDAwMDAwMDApKSkpKShmZWF0dXJlX2ZsYWdzKChyYW5nZV9jaGVjazAgdHJ1ZSkocmFuZ2VfY2hlY2sxIHRydWUpKGZvcmVpZ25fZmllbGRfYWRkIHRydWUpKGZvcmVpZ25fZmllbGRfbXVsIGZhbHNlKSh4b3IgZmFsc2UpKHJvdCBmYWxzZSkobG9va3VwIGZhbHNlKShydW50aW1lX3RhYmxlcyBmYWxzZSkpKSkpKGJ1bGxldHByb29mX2NoYWxsZW5nZXMoKChwcmVjaGFsbGVuZ2UoKGlubmVyKGVkMzBmNmYwNTlmMzFhOWIgZWI1Y2JmMDc1NGJiNTM5ZikpKSkpKChwcmVjaGFsbGVuZ2UoKGlubmVyKGNkOGRlNGUwZWQyNzg1ZTIgZDgwYTJjMjBmMTUwOGFiYSkpKSkpKChwcmVjaGFsbGVuZ2UoKGlubmVyKGQyOWEyYzRhMWUzMWI2NDUgYWNlOTU3MzE3ZjBhNmUyNCkpKSkpKChwcmVjaGFsbGVuZ2UoKGlubmVyKGE3N2ZlYzkwNDVhNTZmMWQgMWQyYTU1M2ViODU3ZDdkYykpKSkpKChwcmVjaGFsbGVuZ2UoKGlubmVyKGUyODE3ZjRmN2QwYmI4NmIgYjBiM2I5MDYwYjU0NzQzNykpKSkpKChwcmVjaGFsbGVuZ2UoKGlubmVyKDc3NzM2OGM3ODg0MTZkN2UgY2QwN2Y2MGVmNDMzOTM5MikpKSkpKChwcmVjaGFsbGVuZ2UoKGlubmVyKGIyZmZiOWEyMjllNzEzZmQgZjZkNjgyZmJjODlkYzkxYikpKSkpKChwcmVjaGFsbGVuZ2UoKGlubmVyKDBkNTU5OGE4OGFhMzMwMDIgNjcwYTNlZjkwNjFlNTUxZikpKSkpKChwcmVjaGFsbGVuZ2UoKGlubmVyKDU3MDNiYjI3ZmE2ZjdhNmMgYjY2MjA4MTJiMmIzNDM5ZCkpKSkpKChwcmVjaGFsbGVuZ2UoKGlubmVyKDg1ZWFiY2NiZTFlMmUwYWYgNTkxOGY5YjE5M2U1MTg0YykpKSkpKChwcmVjaGFsbGVuZ2UoKGlubmVyKDA2YThlZjhkMDNhM2FiNzcgOTVhNmIyZmEzOTFjMTRiNCkpKSkpKChwcmVjaGFsbGVuZ2UoKGlubmVyKDg0NzBlYTQ1MWUxMWRhM2IgODg1ZmUzNTRjNDNhZmUzYikpKSkpKChwcmVjaGFsbGVuZ2UoKGlubmVyKGFkYWRmOTkxNTJjMjcwNmQgYmJhZGRiNmRjZTZmNTAzMykpKSkpKChwcmVjaGFsbGVuZ2UoKGlubmVyKGM1OWI4NDRkYTY1MzgzNTcgZTFkYzc2YzBkOWNmMWM4NSkpKSkpKChwcmVjaGFsbGVuZ2UoKGlubmVyKDUzYTI3MWFlMzNlN2EzYmEgZjk5ZTJiOGY2NmE5NjIxMSkpKSkpKChwcmVjaGFsbGVuZ2UoKGlubmVyKDBmY2VlOGZjNWMwMzIzMzggNTAxOTE5ZTNjOTQ1YzMwYSkpKSkpKSkoYnJhbmNoX2RhdGEoKHByb29mc192ZXJpZmllZCBOMCkoZG9tYWluX2xvZzIiXHIiKSkpKSkoc3BvbmdlX2RpZ2VzdF9iZWZvcmVfZXZhbHVhdGlvbnMoMTg0M2Y4NjMxZWEwNTQyMyAwNGIyNmI3MThkOTRkNmJkIDY4MWRlMDQ0NGEzZGQwMzMgMzBiMzU3NmFlNzAxNDYxNykpKG1lc3NhZ2VzX2Zvcl9uZXh0X3dyYXBfcHJvb2YoKGNoYWxsZW5nZV9wb2x5bm9taWFsX2NvbW1pdG1lbnQoMHgzRTA4NjI5RTM3RDZFQjNGRjk4RDExRUY5QzJBRkQ5RDJGQjk2NTgzRkFBOTBERUE0NDAyQTg2QkE0MjdENDY4IDB4MDJCQzM4NTk5Q0JBMERCOTRDMTQ0QTBBQzEzQzU3NTM1MDM5MDJEMzhDNjZENDZFM0VGQjc4MjM3N0I2NEU1NSkpKG9sZF9idWxsZXRwcm9vZl9jaGFsbGVuZ2VzKCgoKHByZWNoYWxsZW5nZSgoaW5uZXIoMzM4MmIzYzlhY2U2YmY2ZiA3OTk3NDM1OGY5NzYxODYzKSkpKSkoKHByZWNoYWxsZW5nZSgoaW5uZXIoZGQzYTJiMDZlOTg4ODc5NyBkZDdhZTY0MDI5NDRhMWM3KSkpKSkoKHByZWNoYWxsZW5nZSgoaW5uZXIoYzZlOGU1MzBmNDljOWZjYiAwN2RkYmI2NWNkYTA5Y2RkKSkpKSkoKHByZWNoYWxsZW5nZSgoaW5uZXIoNTMyYzU5YTI4NzY5MWExMyBhOTIxYmNiMDJhNjU2ZjdiKSkpKSkoKHByZWNoYWxsZW5nZSgoaW5uZXIoZTI5Yzc3YjE4ZjEwMDc4YiBmODVjNWYwMGRmNmIwY2VlKSkpKSkoKHByZWNoYWxsZW5nZSgoaW5uZXIoMWRiZGE3MmQwN2IwOWM4NyA0ZDFiOTdlMmU5NWYyNmEwKSkpKSkoKHByZWNoYWxsZW5nZSgoaW5uZXIoOWM3NTc0N2M1NjgwNWYxMSBhMWZlNjM2OWZhY2VmMWU4KSkpKSkoKHByZWNoYWxsZW5nZSgoaW5uZXIoNWMyYjhhZGZkYmU5NjA0ZCA1YThjNzE4Y2YyMTBmNzliKSkpKSkoKHByZWNoYWxsZW5nZSgoaW5uZXIoMjJjMGIzNWM1MWUwNmI0OCBhNjg4OGI3MzQwYTk2ZGVkKSkpKSkoKHByZWNoYWxsZW5nZSgoaW5uZXIoOTAwN2Q3YjU1ZTc2NjQ2ZSBjMWM2OGIzOWRiNGU4ZTEyKSkpKSkoKHByZWNoYWxsZW5nZSgoaW5uZXIoNDQ0NWUzNWUzNzNmMmJjOSA5ZDQwYzcxNWZjOGNjZGU1KSkpKSkoKHByZWNoYWxsZW5nZSgoaW5uZXIoNDI5ODgyODQ0YmJjYWE0ZSA5N2E5MjdkN2QwYWZiN2JjKSkpKSkoKHByZWNoYWxsZW5nZSgoaW5uZXIoOTljYTNkNWJmZmZkNmU3NyBlZmU2NmE1NTE1NWM0Mjk0KSkpKSkoKHByZWNoYWxsZW5nZSgoaW5uZXIoNGI3ZGIyNzEyMTk3OTk1NCA5NTFmYTJlMDYxOTNjODQwKSkpKSkoKHByZWNoYWxsZW5nZSgoaW5uZXIoMmNkMWNjYmViMjA3NDdiMyA1YmQxZGUzY2YyNjQwMjFkKSkpKSkpKCgocHJlY2hhbGxlbmdlKChpbm5lcigzMzgyYjNjOWFjZTZiZjZmIDc5OTc0MzU4Zjk3NjE4NjMpKSkpKSgocHJlY2hhbGxlbmdlKChpbm5lcihkZDNhMmIwNmU5ODg4Nzk3IGRkN2FlNjQwMjk0NGExYzcpKSkpKSgocHJlY2hhbGxlbmdlKChpbm5lcihjNmU4ZTUzMGY0OWM5ZmNiIDA3ZGRiYjY1Y2RhMDljZGQpKSkpKSgocHJlY2hhbGxlbmdlKChpbm5lcig1MzJjNTlhMjg3NjkxYTEzIGE5MjFiY2IwMmE2NTZmN2IpKSkpKSgocHJlY2hhbGxlbmdlKChpbm5lcihlMjljNzdiMThmMTAwNzhiIGY4NWM1ZjAwZGY2YjBjZWUpKSkpKSgocHJlY2hhbGxlbmdlKChpbm5lcigxZGJkYTcyZDA3YjA5Yzg3IDRkMWI5N2UyZTk1ZjI2YTApKSkpKSgocHJlY2hhbGxlbmdlKChpbm5lcig5Yzc1NzQ3YzU2ODA1ZjExIGExZmU2MzY5ZmFjZWYxZTgpKSkpKSgocHJlY2hhbGxlbmdlKChpbm5lcig1YzJiOGFkZmRiZTk2MDRkIDVhOGM3MThjZjIxMGY3OWIpKSkpKSgocHJlY2hhbGxlbmdlKChpbm5lcigyMmMwYjM1YzUxZTA2YjQ4IGE2ODg4YjczNDBhOTZkZWQpKSkpKSgocHJlY2hhbGxlbmdlKChpbm5lcig5MDA3ZDdiNTVlNzY2NDZlIGMxYzY4YjM5ZGI0ZThlMTIpKSkpKSgocHJlY2hhbGxlbmdlKChpbm5lcig0NDQ1ZTM1ZTM3M2YyYmM5IDlkNDBjNzE1ZmM4Y2NkZTUpKSkpKSgocHJlY2hhbGxlbmdlKChpbm5lcig0Mjk4ODI4NDRiYmNhYTRlIDk3YTkyN2Q3ZDBhZmI3YmMpKSkpKSgocHJlY2hhbGxlbmdlKChpbm5lcig5OWNhM2Q1YmZmZmQ2ZTc3IGVmZTY2YTU1MTU1YzQyOTQpKSkpKSgocHJlY2hhbGxlbmdlKChpbm5lcig0YjdkYjI3MTIxOTc5OTU0IDk1MWZhMmUwNjE5M2M4NDApKSkpKSgocHJlY2hhbGxlbmdlKChpbm5lcigyY2QxY2NiZWIyMDc0N2IzIDViZDFkZTNjZjI2NDAyMWQpKSkpKSkpKSkpKSkobWVzc2FnZXNfZm9yX25leHRfc3RlcF9wcm9vZigoYXBwX3N0YXRlKCkpKGNoYWxsZW5nZV9wb2x5bm9taWFsX2NvbW1pdG1lbnRzKCkpKG9sZF9idWxsZXRwcm9vZl9jaGFsbGVuZ2VzKCkpKSkpKShwcmV2X2V2YWxzKChldmFscygocHVibGljX2lucHV0KDB4MEQzREY4MjNGRjY2NjMwNDZCQURFMzAxRDQ5NzE2QjI0RjY1REU1RjQzQjdDQTIyN0Y4MDkyMDU0Mzc0RjA2MCAweDE3ODgwRTRFNzdERTcxQzVERjFEQjRCNzQ4RUUxMkE0MDE2MzVEN0M4NDA0REQ0NkNGOTdFRDQ1NUM0RTM0NzIpKShldmFscygodygoKDB4MDUxQjVGNjc1Q0Q2MDhGRkRFMzkwOTA4MTc0RjI3RUYzRURERjFGQUEwMEQzNzZGRkZDM0RDNjAyODI5NTQ1RCkoMHgwNTc5ODlGNzNCOUJCOEYwM0I2RTM2NzIzOEZDOTU2NDZERjlFMjE0RkM3MUREQTFGRUUyNjY5NkJENUFGQzAzKSkoKDB4MDhEMTNFOUZGREZCRkI0Q0JFQzIwRjM0ODA2QkEzNDA5QUI1QzNFMTE5NUIzRUMzOUEyRUYwNEFGREFFOUE1QykoMHgzRjg5RUFGQ0M0RkZFMzcwOEM4N0UyNEMzRTA2RUE3QTdBMTRFNUUxOTEyMkY5NTAxRTI1NjMyNzlDNkQzNkY5KSkoKDB4MTBCMjFFMzlEOTk2REI4REE2ODdEMzUxRjkzNDg5QjJFRTIwODY5QjVCRUY2NzgwNzhFMDQzRDVBQjczRUY5MSkoMHgwNkZCNzZGRDQ1NzMxOUExMjgyREJGQjIyMUUxQUI3OTE3QjQ4RDNEN0VFMkY1NTA0NEIxNkEyMEFGQjg1NzVGKSkoKDB4MTE1MDIwN0QzMzJFRUQ0MkIzRjA5NUFDQjVFQ0I1Qjk5MzQzMjVCMDgyMDBBOTNFOENFQkY5NDEyOEUxODVGRCkoMHgxN0NCMTE2Q0FGQkY4OEM3REM1RENFREMxNUIyMzcyQTM0QjFBQ0YxNUMwNTY3QjU2QTBCNjQ5QThEQzIxRTQ3KSkoKDB4MjBBNzI5QkYyMUU5RTk4MkY4RUMyNjg1NDk1NTI3NDA4MEZCRUI2RDVCNkM2RkU3RjhDMDgwRjFFQUMzOUQwMikoMHgxQUNFREExM0IyQjBFNzJFRTJCNThCN0VEM0MyQTIzQTk4Mjg1NTg4MDU0QkY2RUIwNTA3OUM5NTAyRTkxQTQwKSkoKDB4MzY4OTM1NUEyNDQ1MDdCMzU5NTc0NDQ4RDY3NTU4NDU1RUM4RDk3MkM0OUJGN0JFM0U1QjQwMDRFRTY0RjMwRSkoMHgwNDczMEREODczNTMxNTIwRUU5MzA0RkJCMEE5NjYxQTE5MDQxQzZCMUFBRTY2QTBGRjk2RTEzREFDMENCRUVCKSkoKDB4MEExNDgxNjlDMzU1NUZEMzdERjVGMzcyMjExOTVFOEE0MTYwMDY1QUIwMjdENzkxQTI0Mzk3RjIxRUQxOTU3MSkoMHgwM0Q1RkM0MDA1QTM2REJDRkFGRkI0RDFENDFGODgyQ0VEOTZDRERBODk1NkRGN0VBMERDMTNCQzlFNzIxN0VBKSkoKDB4MENEMDZEODA0NjJFQUM5RkU1MEQ0QTRDQ0IxRDE3QjEwMTU0RDNCQUFBMTI5QTQyRDBEQkQ0RUVCNkNFNTU5NCkoMHgwNUYwRkM2QThCRDZGOUNFOTM2NUNCNjlCMURCMUQwQ0U3Q0FBNzZDNDI1RjQ1MjlFQUM2MUM2M0E4NkIxMDE3KSkoKDB4MDc0QkE1REM2ODgwOUFCMTE0MzdGOEJCRTdFMTMzRTUwOEU1QUIxNDM4NUE5MDFGMjQ4NzhGRUEwMkNERURFRikoMHgyMjY2MUQ2OTQwQTE0RjkxOEVFQ0Q4OERBOUI0NUU3RDBFQkFEODZGQ0NFRTEwMDg2NkMxNUUzNENFQUYwRDFFKSkoKDB4MDdDN0QyQjk5NDI2RDlENjcyNDk0Mjg5ODY5NkMzRTY3OTEzN0U2MjNCQUJDRjgzNzM3RjRBMkVBRjY5NEM2NCkoMHgwMTBCNDcxQkQ1NDY2MUI4OTRFMkVFMzMxREI5NEQ2RURCOTM5OTU1MUYyNzBFN0FERkQ1Q0VCM0IyQjYxNjkyKSkoKDB4MkIwRDIxODEyNzlGQUZGODE2QzIzOEUxQzJFRDFFODMxODREQ0U3QTVEQzNFQkJGNDJFNEQ3MUU4ODk4Njg1QSkoMHgzRDMzMzQ1RTQ0REI5MUYwRDk1MUEwQjc5MTg5MTE0OTY3RThGQzk1QjVBOTY0QkQyRjAxMkEzN0ZGM0FGQzNCKSkoKDB4MDc1QkQ1RTNENkEwNTJEQ0U2RkQ1NTIyMUNBMDY4M0RFNUE1NDc1NUIyNTZCMTYzRkE0NEI4MEQxNjUzOEI4NSkoMHgxQjI3Rjc1NjQ1RThBNzRFNzYyMjRGMjI0NDc2QTI0QjMwNTYxNjE5NzA4MDM4ODA0OENEMjFGOUE5MUNDNDBCKSkoKDB4MjkzQ0ZFQTBBNkM3RjA1RkIyRkQ0RkYwMjFGNTRBNzA5QjQyMURDN0IzQ0IyN0VCQzk5NUM1QzIzMjFBNjNDRikoMHgxMkY3QjRGQjY5M0RFNjA0NEE4NjM3NThBREY5RDUzMTRDQTI1RTlDMjI4ODhFNkM1MDJFRkYxMjRENEY2OTg2KSkoKDB4MzIwNENDQjExOTg1NzMzM0Q5NTg3MUNFNkJCMkM2NEM5OUMyNTY5MDZGMjAzNzM1OTZGQTZDNzBDN0ExNkZGNykoMHgzMEFBMDZFRUI1RTQ0RDFFRTVBNTc3MjU4REYzNDQ3Nzk0QTIwRUUyQjdDMDU1Nzc0NUJGMzIzOTVDQTIxMkUzKSkoKDB4MENGRkU0QkU4OEI2NDdBQjJBNURDN0YwQTQ0RTdEOUYxREJDNDc5MDhFODhFQ0E1RjgxMjU0RTU5MEFBNjUyMikoMHgxQ0U3NzAwMzRBODA1MDkyQkE1ODNENDQ4NTg3QzU4NkNFOTUxNEU3QkNBMTZCNzZCNzhFODg1N0FDMTk0NEYzKSkpKShjb2VmZmljaWVudHMoKCgweDI3MkI0ODk2NjgyRkZCODNGOTMwMTMzQ0QxOERENDg2M0Q0NjdDODc0NUJFMEZFQzA1RTA5QTVBQTQxMTEzNkIpKDB4MzA2ODMxMDBERUJFRUM3OTk1MzYxRTA0MjJFMjQwQzgzQzE4RjIwRjM1MjQ1OEFFNDk5ODM3MTk1OEMxRjZCMSkpKCgweDAzMDZCRTQ0MDFGODEwOEQwODIxMDFFRkNGN0FGMUM2QzFBODNGMEJEMEY5NDYzQTg3MDYyNEZGQUU1NTVBNTkpKDB4MDRBRjU1NzJFNjAwQUM2RDUyRTFFNjQwRTI2NkY1RDk2NEE2MEQwNzE2NTlEQ0ZCQUM5OEY5OThDQjIxODk2NCkpKCgweDE2OEIzNzhCODUxQkZFMkQ2MTIzN0ZEMjVFRERFMjAyRTNGOUExNUU3ODRGRjVCREIyMjM2Rjk3ODM2MzI4M0UpKDB4MzQwMjg0MThDMTc2RjY4NDFFQTgwOTE3OUQzM0EwMjk0NzY5NEM0OUFFN0M0NDQ4MDgxMzA1Q0MwMDMzMUNENykpKCgweDBFQzZEODcxQUExMTVBQzQwRTQ0RTMyNTFDRTA1QzZGQzMxODlGQ0QzNkQ4OUM5RUU5M0FDOEY5Nzg4RUZGMDQpKDB4MjdDRkI1Q0NFNEE3RUZERjY4Q0ZEQUI2MDMxM0RCMTkzRDBCRkU2RDMzNzMyODlCRDc3NzhFRTA0QTZGMkZBMSkpKCgweDBGNzYzODE4RjZBMkRDMUVGQ0E3NTRFMDE2RTg0RDcwRUNBMTFCRjRCQkNBQjJFRDgyODc0QUQ3Q0E4Q0IyOTUpKDB4MkU3MjJCODlGQ0IzMTlEMTc3MjkyNTQ3NDM3MzI3MkY3MkU2ODVFMUIzMEUwOTgxMzQ3RDYzNzhCNDIyOTQ2QykpKCgweDA4MUI2MUREREU5Qjk3RkIzRDExMjA5Q0FENEUxMzVBNTgzMjE2OTE2QUI2MDFFMTVDODYzQjY2Rjc5Q0I3NEQpKDB4MDUyMzBDQUQwQzdGNERGMDhDNDU2ODI2NURGM0FCRjhDNjkzQ0RFRDI0Q0I5MkQyOEE1RjQ4QkUwODU2NTJFOSkpKCgweDBGNTE0QUFFMTA3NEQ5M0QxMkRCNEI0NkVCNzkzNTU0RTVBNzExOTU5NUFDRTgzN0VENTBEQkE3QTFENDMxNjkpKDB4MjQ1M0ExMEQ3QjczNzM1MDI1OUNGNTMyMEU0Mjk2QkVCNjRFM0UyMzhDNjI5MTNDMTI1NTJDQkMwNzNFQjUzMCkpKCgweDJEMjk0MkM1RERGQjQ3OUMyMTFEMzNCNTZBN0FFMEY0MDdFMzkwOUVFMjRFRDZCOUUxQzVDQ0RFREFFOTczRDkpKDB4MTdDNUIzOUJGQzcyRTI0NkZERTk4NjdFQzFBNzc0QkI3REFGRkU3RDY4M0U0MEMyRUE1NkNGNzI3RkJFRTA4MykpKCgweDM2OTg4NUQwRjJGNkI2NDRFMkVDMDNDRDhCM0NEOUEyOTNFRUFCODc5NUNFNDAwRTJGQjU0RkM0MzJFM0U3RDkpKDB4MkM1N0E3NzQ3NTUyMDA3QjRCOEVDRjQwMzREQkZDMjA4RUQzRjcxQTk2QTFEMDJBMThBMkJFQTNGMkU2QkYyMCkpKCgweDJCRjJFNzhDODFGNzU2RkMxMzMwQTQzMjQ0NjMxOTdDRDM5RjlGOUIzNERFNTgxODI3QkExOTAxQjY4MDJENTgpKDB4MTk3REVEQThDQzA2RTNBQzYxOEZBRjQ0RDBCNjg4NDYxRDRDNzBEOEU2OEQ5MDE5N0QzRTU0M0U1Njk3N0MwMikpKCgweDA2NEUyQ0U2NTdBNEMzODZEOUQxNkYyOTNBNDBCQTNENzExMjVFNzk5NDlDMzgzMjQxNkFFNTAzQ0RBQTBFOTYpKDB4MEIwNTBFNTcyNzhFNTVFQ0VBMzk5NUI1RDEzQjRCMzY1RjA2MDJFQTY5RTlENzA2MjE2NjJCMjQxMjUyMTU0QykpKCgweDMwMDlFQ0YzQjhCRjcyREQ2NEJDQ0IwNUY5RDQwNUYwQ0Q3QjM1ODRFQzhDODA4OUI1NTNCRjExOENBREU1QTgpKDB4MDQzRENCQzg3RjA0QkZCRURFNEVDMjVFNjdGQjNDQTcwOTcwRkNCNEE5NzdEOUQ4QUZEMTQ2NzVFOTU5NDMzMykpKCgweDI1MUIzNzk3OURCQTkyQ0I0NTNBRjhFNkM2NzZDNEYyMUY3Nzc1NDg4QjhEMjVCRDg0N0EyRkZGNDAyMTQ1NUUpKDB4MTJDOTk3MzM1MDk2NzFFRDZDMDAyODg1NDNFMTdDMkRCMjUwMUU0RUY3NjlEQ0Q3NTk1OTg4MjYwQThENTIxRSkpKCgweDEyQ0M3QjY1QTgwQjlFMTQzRkREODMyMEY3Qzk2OTQ3Mjk0N0M5ODVDMzdBOTQzQkYwMjM4RDQxMkMzRjY4MjgpKDB4MjBGQTgzNTRDMDIyM0ZEMTI5MUM2Njc3MzMyQkZBRjRDNUQyMzVCREZERDMyMTY2MUZGQjJFOEMxNzhDMzU2RSkpKCgweDBBRDQ0NEI5MzA3RUUzNUEyNTRGNDA1Q0NDNzkwMUMyNjU4RTg5OTkyRTlBREI0NjAxM0E5NkU0QUEzNDg2MEIpKDB4MUM2NTc1NURGMDMwQzgwNUEyRjUyNjFEMUFFRDAxOTI3Rjg4QzU0NEFGMTgxODJBMUM4NUEzODVDNDg3Qjc4NykpKSkoeigoMHgzNkE5NkUxQkFGNzUxNzk1NUIzNjEyOTdDREIyQjIzM0IxMkYxNTQwMjdENEE1MDYyMUExNTFFNkY4OUY0RjFFKSgweDI5NUFEMDYxNjE4NjU0OUU4MEM2MTk0NTk4NkMxREE0NjA2QTlCRDcwQTI5NEZGMjhEMTQxRDA5REVFRjU0REQpKSkocygoKDB4MjNEMThBQ0UxQzdBRTIwODQ5RkM3N0YyODhCNDk4RTAyMDE1OEYxMUJFMjhGOTI5MjVBNENBRDI5MzUxODQ2RikoMHgwMzg3QTZCNEY5RTBGRDExNDM3RTA1M0VBODZBRDEyQ0UyRkYyREVGMDA2MUY2QzRCREIyOEFDNzE1NEQ5OUVCKSkoKDB4MTAxQkQzRTYxNzMyMUZFRUU1MjEyQzE3RkFCRDkzRjk5QzMxRjJBNzQ0RThBNzM1MDBGN0JDQjNDQjVGRDUyNikoMHgxRDVFMDcyNzRFNjZBMDU2NEMyOTQzRjg5QTE3ODA0NkYzNzAwRDQ1MEQyMjM1OTM1M0VFQzM2QjNFREM4NEUyKSkoKDB4MzhCMDk3ODZDMzk2MDVFM0Y5QjNGMTM3QjJDM0ZDQkE2Q0ZCRTg1OTJFMDIzMkM0MDUzQjQwNjU5RDlBODYxNikoMHgwRUM1RDg1NzNFMTlFQTgwODcyMUQ2QTgyOTg0Q0RGNjE4MEFEQkU4MkJCOTEyMDEzQUVBNkY4MTNFMzA5OTg1KSkoKDB4MzlFOEM3RjI1Qjg0ODAwQkM5Mzk2REY0NTM4RkQxRjA3ODg4NEVBQjQwQ0M1QTg0RjlDRkMwODNCRTRGREUwOCkoMHgxQTNDMDAzQ0M4MDIzNEMxMkUyMjM0MUMzRTQ3RjEwNUFBQUE4MTEwNTVDQjVDMTZDMkEyMDRGRTlGM0VBNDIwKSkoKDB4MkUwMDE0RjM2NTA2RjgxMDYwRTk0NjE4QzIxRjYzQjQyRjRCNUIxNDgxQjk3ODU3NUMzRUVENEYyMUYwRkQ4QykoMHgxQzAyRDE3MTIwOTZGRjg2OUY0MjhEM0YyQzQ2QUQ1RkNGRjJFRkI3NDIyOTMxMUZDRUY3RTI5RDZFRDE0OUE2KSkoKDB4MTFERTUxNTYzQUI2MTBDRDNGNUFBRjJCMjJCRjI3QkVBQTAyRDQ4RTdEMzc2QjE0MzkyNUQzQzA1RjQ5NjQzQikoMHgyOTg0ODg0Njk2RkRENzU2MTEyNkJGOURGRUMwNkE1NDk1QzVCNzFBMjg0MEExNDc3M0UyNTc1NzFEQ0YyMDA1KSkpKShnZW5lcmljX3NlbGVjdG9yKCgweDJCMTU3RkRCNjE5NDA1RjBCNkE0MzRCQThBRTI5OThDOTNDMEEyMjdERTRBQUJENjE4RTdGQUFFMEZBMEU4NzkpKDB4MTJBNEQ0RTQwQjQ0NkFENjQwOTlDM0I1N0M4NkJGNkM0NkUwRkQwMDFGOUY1QTA3OTZFODMwRUMzODQyOERFOCkpKShwb3NlaWRvbl9zZWxlY3RvcigoMHgyRDI0MjA0MEUwOUM2MTAwMDdFRDdCNDMxN0FFNUQ3QTIzQTVFQkQ1NEU2MzgzREU2RTQ4QzgzNzkyOEIxMDQ2KSgweDJFNEYwNzY5NTMzRDkyMzIyM0ZENEY4NUE4QkRBQ0VGNzgwNjdFRTI3QkVEOEZEM0QyNEM2NDJEMkU3QTI5QUIpKSkoY29tcGxldGVfYWRkX3NlbGVjdG9yKCgweDJBODQ4OUU3MTBDNjk3NkNCOTk3QjM5Njc4NUM1QTJGMTExQTA4OEM5RTdBMUMwN0MyMjhCNDkyRDA4MUUzQzUpKDB4MDQzRjYwQzlFNDQxMjc4NTM3REI0QUMzM0Y3QjU5MzZBRDQyMzc3Njg1M0I0Mjk0QUE5NUFGMTBCQTBGOThGRCkpKShtdWxfc2VsZWN0b3IoKDB4MjRFOTBDNjYwOEI1OUU0MkJEQjM0NURGRTE0RTI3MDM2NDU4QUQzODBEOEJGRDZGMkY3NEU3MEMwMkZGOTc1NykoMHgwRDQwRDFEODYzOUM2MjBDQkQwOUI1N0Y5QTJCMEE2MDQxRDc2QjAzODY3RjlCMkM2QjhCMUNGODdDMjVDMkYyKSkpKGVtdWxfc2VsZWN0b3IoKDB4MUNDQTRDNDY5RDU0Q0U0NTQ5QUE3NDcxOTVCNkM5RTA3NzZGMDk3QTQ5NDlFOTFBOUNCRjg2MDc4RDdFNEE5QSkoMHgyRDZDMUVGMzgwMjU3NjAzRUE2QzYyMkIyRjMyODZBMUU1QTI0MTU5MDQ3RkM5QzUxMUQ3N0ZCNDFDNTk2QTdFKSkpKGVuZG9tdWxfc2NhbGFyX3NlbGVjdG9yKCgweDI4RkM0OTMxMjlDRTMyQ0RCMDI0QjQ3MUIxMEVFNUMxQTQwMDlDRjFFQ0YwODI2N0ZDRjYzRUJGRDI0Qjk2OUMpKDB4MEFCNzdDMjFDMzUxRTQyNTc1NjA0QTIwNEZGQzFDNTQwNjQ1MjZFOUM0OTUzNDk3NzA0RUJCMzBDQ0ZEN0RFNSkpKShyYW5nZV9jaGVjazBfc2VsZWN0b3IoKCgweDI5Mzk4OEEyRkMzMzFFRDY5MDM0NzkzMTlFMDA4QzEzQzRDNkVCMUVDMjcxNENBMEJGM0I2QTRCM0Q2MzVFMDMpKDB4M0QyQzM2NjAxMzU0MjEyNUQ3OTExMjNEMDQzOThBMjdCOUZBMTRCODY4QTlFQzEwN0E3MkNENzdERDVFRjkyMSkpKSkocmFuZ2VfY2hlY2sxX3NlbGVjdG9yKCgoMHgxMkVEQjBFNzNFRDdCMERGRjFERDYxM0U1NDkwNzg5RUM5M0U2RkYxNTFCODczMzhFNTYzNjEwM0ExRUI5OUU2KSgweDMzQkRFMTY2NzFDRTNCMzI0MUExMTlFQ0Y0MzFEQjUwOTIwQzFFRDM5ODdBM0ZGQTgyMTYzOTFBOUFFODlENEEpKSkpKGZvcmVpZ25fZmllbGRfYWRkX3NlbGVjdG9yKCgoMHgzOUQ1RjNBNkI3RTQ0OEI5NjhGMTVDMTlCQzY4NDRBRDZDQzE2NDczQjBEMEYzM0NFRDNEQ0VEMjM4QUYzQUUzKSgweDJFNEI3OTY0MENEMkMwMDkwMjg2NDYwNTYwMEMyNjBBMjU4NUYyODZEQkJFNjQ3MzBGNUY1Nzg5QzJGMDg4NkIpKSkpKGZvcmVpZ25fZmllbGRfbXVsX3NlbGVjdG9yKCkpKHhvcl9zZWxlY3RvcigpKShyb3Rfc2VsZWN0b3IoKSkobG9va3VwX2FnZ3JlZ2F0aW9uKCgoMHgwRjA1RjY2NzlCQzYxMDIzNTk3MUNCNDQ5RkQwMDUwMzhCM0JDMkQ2NTM2RDFFQ0JFRUQwNEE5NEUyMTI4ODU4KSgweDA1Q0M4REIwNjk2OUQxQjJCRjc4QTVEMUU2QjI5NUYwMTJDMjU0NkFFNkM0RDYyOEJENzg3MzNFNUM3OTdENkEpKSkpKGxvb2t1cF90YWJsZSgoKDB4MTFGNDczNTUyNDhGQjkzQkRGODM2RDQ1QUZBQkJBNkJCQjhBRTU5N0I0NkI4QTcxNDA1RTk4QjRFREU4M0VFRCkoMHgyRTVCMEQ3RjdGRTJEQTdDRjIxRkEzRUZDNTM4NjQ2QjI4Mzk3MzEzOUJFQkI0NDZFNEM0ODY0NDM1MjY5M0FCKSkpKShsb29rdXBfc29ydGVkKCgoKDB4MTQ1RUU3OTQxMjg2OThFMTJGNThBRDJFRTYzNkFCRDNEQzIzOTQ2MDRDN0Q0NjgzMDNCNjY0MDlDNkE4MjJDQSkoMHgyRjVDRTBDNUY2MTE5QTYzN0IyMzNEQjNDNEVEMDVBODVDQUM1MjlCOTY1MDVBMjgxQTQzNDE5M0VDMkFCQzQwKSkpKCgoMHgzNzlFRkVFNzlCRjVDNjI2QzYyM0E0OTJDQTNBQjBCNEI5MTA0RkQ0NEFFODIyODcyOTY3QUExM0Y4RUM5MDc1KSgweDA3OEIxMzQxQTMxQ0VEMzhCMjc0OTkyMjc1N0E4OERGMjJCRkNFQTFDM0JFNTNEMDZFRDMxMUNEMDEyQzUxRDUpKSkoKCgweDM2QjU3M0MxMTJGNkFCNEM1RDA3MTU5OEY2MTQwNTZENDhFM0E1QUMxMjQ4RDlDMUUzMDYxMzQxN0ZERUUwMEEpKDB4MTdEQzMxODkwREYxRDcxRDYzM0VGNkUyRjg5RTQzMzdFQkM1NTQ5M0E1NUI1QkU4MEVDNjc4QUJGQjdGOURFMykpKSgoKDB4MDU4NEZGNjMyNjJFM0VFNjNGM0I0OENFNTU4MUY4NDg4OUUyODA1QjI1OUJEOTFEMjQ1RTNDRDc2RDQxNEFBNikoMHgzOUIwNDgzOTBGODg4REQwOUYxNzQxNzQ0OTBBMDI5QTE4M0I2QUEyRTg3RDc1QTFGN0ZGRDdFMDc5QzRFMDBBKSkpKCgoMHgwQkIyQjNERUIxQTUwQzRDMTE2OEExQjU4OEEyQ0RFMjcxREU0OUNCODM5MTI4NTFBRjNCNEYwNjY1REUzNEVGKSgweDIwRDM1MUJCQjU0Rjk2MUI1N0UzOTM4OEQxMUNFODYyOTkzQ0RFQ0FGNjMwQ0JDNkIzQTdEODFEMTRFNjBFNUYpKSkpKShydW50aW1lX2xvb2t1cF90YWJsZSgpKShydW50aW1lX2xvb2t1cF90YWJsZV9zZWxlY3RvcigpKSh4b3JfbG9va3VwX3NlbGVjdG9yKCkpKGxvb2t1cF9nYXRlX2xvb2t1cF9zZWxlY3RvcigpKShyYW5nZV9jaGVja19sb29rdXBfc2VsZWN0b3IoKCgweDBBOTQ2NjU2QkEzMTk2QjU4N0QzNzhGNDk0MzM5M0VDNzE4MkU2RkJGNDg2RjQ0NUQ4RjI1ODY1QzQxNUIyN0YpKDB4MDNEN0M4QURDM0ZBMEQzODBCMEY4RDY4NENGQkRFMTZEMEI3NzE4NTQwNDJBRDBDQUY5MjA1QkMxQTMzMzA0RikpKSkoZm9yZWlnbl9maWVsZF9tdWxfbG9va3VwX3NlbGVjdG9yKCkpKSkpKShmdF9ldmFsMSAweDFGQUMzQzRFNzUxQTU5NERDRDAzNkRFRkI4QkRCNjE1Qjg5MjI4QTRBQzAwMUFFMzRCNzk3Q0Q1RjgzMjY5MDQpKSkocHJvb2YoKGNvbW1pdG1lbnRzKCh3X2NvbW0oKDB4MEM4NTkxNjQyQUM0NEEzNzgzMUI3N0FEODJFQ0YxNDkxMkYzODg2MEI2ODEzMDIyNDAyODY2NDU5MUQzRTE0QyAweDFEN0Q2NjA3QjdERUIyRTgyNDJDNzY2RUJCNjY5MzA5QUU5MTZCMDk1Q0QzRUQzOTgxNDE1NUE1NUE1N0IxMTIpKDB4MTg3RTVCNTQzOTEyRUI3NDAxNTYzRjQ3OUM2MzVCOTZENzVBQ0UzM0IwREY1NjRGRjcyRDE0ODJCNjc3RDczRSAweDEwNjlFMkYyNDUyREI0MEE5NTU0OTJGREU5MzI2MUU1ODQ0RTk5OEY1REY2Q0VDMzY5QUI4MUYwM0QzNjc1QTQpKDB4MTU5MzNCQjhEN0RBOTg5QUEwNUY3NkFDN0Y2RDcwQkYzMjAzRDE1OEIwQ0Q3NEJEQzZBQjFGRkVDQUQ5RUZGRCAweDI2RjczMzFBNjMyNUM5M0NCMUZEMDE2QkFBODRFQjQxRkJGQ0JFNTRBRjlERDUyMUFGMzRCNkMyNjVCNDM1NjApKDB4MDFFMjgzMkY3MDZDODkwRjFBREJFREMxNjdDMDYxOTExREI4RjM4MTE2QzM2RDk0RjJFN0I3NDBFODA1RDY3RiAweDBFM0JFOEI3Q0MzRENDODcyRUFGRjRBMzNENkNCNzUyNkM2ODhGNTQ4MDlDN0VBMDIyMEQ3NEZGNjU1N0VDMEEpKDB4MjhBNDQ1MDhBNENFM0I0MjJBMzE5NjQwODA0M0NFOUU1RUJDMDMxMTVCNjRGM0Y3Q0RDMUY3MDMyMUZCN0M1RSAweDFBNENDMjkwNTg1M0MzREI5RTRFMTRBNUQ4OUVGMDBFM0RFQ0RDODkwRDhFMkExREREMzA3N0E1QkQ5RjY5RkMpKDB4MTI2RUVDN0Q2OTJEQjhBODYwM0M0OTQyMzBCREU0OUYxQjhERTIyNEUwNjgzRThBRjk4RkMwNjE1NDEyQjMzOCAweDM3NTY0NUUxRTEwMDVGMjYxRjRENzU3N0VBNDU3NEZBOTVGNjkyQ0FDQTI3MUI3NEY4Qjk4REVFRTVBMENCOTcpKDB4MUU3QjQxMDM5QzJDOTFFRDIzMDVDOUFGRTgwNDk0NzY2QzlDODZEMTlDOTFGNTYyNjA4RDhDOUJDRkFDNzY0RSAweDI1NkE4Q0M4MkZCMUJCM0M2MEYzOUYxMDA2MjcwRjAzRENDRDQyNjlFQzFEMDg3NzdCRTBGOTFDRkJFRDJFNzYpKDB4MjExRUNCMDRENDIxRDI5ODZGNjM0MjIzQjYxRDhDM0VBNTEwNUYzMDcwRDBCMEVCRTY4OEIwOTE1RTI5NDRBRiAweDJDMUZDREY1Mzc2MkMwMzNFOEY1MTRCREZFMEZBRDgwMjAzRUJBODlGODUyRjExNzE4N0JCNzM5MTQ0NkVCOUMpKDB4MjA4Qzc2Rjg1NjM5QURERkI5Q0Q5QkQzOURBMkFGQzA2NjkwNkFEODUwQzg3QTVBNERCQzREMzNDODMwRUYzQSAweDIyOUYxQTgyRUFEOUU1MkZGMEU2ODJCQTlGQUVBQUQ4QURGREExRDExNzNFNDZFRkE1MTY1NjVBQkQ1MjI4RDkpKDB4MUUyODRGM0M1NEQ3QTg1NDExOTM5NkY1NjJDMTE3MTE3QzMyQzIyNkVFQjAxRDVGRENFRTBDNTc2MjYxMjY1NCAweDM4NjdFNzZGNTg5REUzMDdCMEE2MTU5RTMxQ0MwRUEwM0JBOUM2MUVCQ0E0MjgwQTU3MEY5MDVBRUNCQ0YzRjgpKDB4M0I3NkU0QkZDQjYxMDFENUEzMTREOTJBNDU0QjI3NzU4QzhCODI4Q0I0RUI4NkFFMUNBMzJEQzhCNUUxREU0MiAweDM1NjI1NjdGREFENDFENzJCQzUzREMxNDU2QkZFRTAwNDZFMkVGQUIyNkE4RDJGQTlFNzRCQzAwREM0MkE0QkUpKDB4MDA1N0QxMEJENUE2RjhFNEI2RDVGRDJBRkUzQkI5NTZFNDgxRDg0OEMxNjVBNEZCRTdGNjg4MkMyQTU5MTBEMCAweDM0OUY0ODc3OEQzRkNGQ0E5QzA0Q0YyNEQ1RDY2MEI1MjYyMjMyRjZGQjlBOEU4OEYwNTIyMkJFQkNFN0IzNDEpKDB4MkQ5RjExMjJENDk5NTkwNDc0QjNBNEVGQkRCNkQzRDYzQTM4NDQzRTlGMDk5OTIwODAxOUFCRjQzMTlFOEJCMyAweDNGMjc4REFCNEU2NkI2NEU3QkY0QkU1MTMzQjg3ODMyOTI1NTYzRUMyQTU2NTA5MkRFNDQzQjExRTU5MjMzNUEpKDB4MzgwMDNDMDlFQUU2MUVFREU5Mzg5MDVDRjUzNEM5NzhERDYxMTFFRjA4RjBEODcxRUY3RUY5NkQ0NDg1RkFBQSAweDJDQjlDMEUzMTg1RkY0ODkzRkJBREEzOUQ4MUY4RkMwMEUzRENBODFBNzIxNUY0MEU5MkVCNjI1QjFCRTczQzkpKDB4MkUwNDM0MDVBMzUyNTMzRUE1MjNFQkQ4MTE3NTA0RTAzNkJDNEVBQ0VDNDIxQTBBRUM0NkZDMUU5RkE4RENGNyAweDM2RjRFN0ZDNUVGREYwQUM5MEVDRjA1MUQ1QTRDQUJDOUI1MEM4OTNDRkQyMEU1MkFDRjQ4NENDRDY2OEVGQ0QpKSkoel9jb21tKDB4MjRCMDQ3NDE5NjcwQUQ2NjQxMjdFNjQxM0MyMTdFN0RCQzdFRkNGRDZERjk5M0I0N0YzMTdENEU5QkM2MDY2QSAweDE1QUM1RkVFMERFNkI2RTNDMDFBMzZBQkVCMTBDNzRCNzQyQUY0M0IxMEMwRTBBRjk3Q0Y5QzY1MkQ5QUI0ODMpKSh0X2NvbW0oKDB4MUEwRkNGRTFBMTI5MTNCMTlGM0RGRkRDQTNCMTFBMTg0M0M1QTQ1RThFMjBDMjNERTExRkNCMTM1NEM1OTk3OCAweDE4NjVGQjg1N0UwMEY5OTA0NEY4QTBFRUQwOTVDRUEzMUU3RjE4RDIwMTUxNThDMjFFNjBDNzc2RTQyNTg3MDYpKDB4MTZCMTUzNDhENEU5ODFCOERFQ0MwQ0ExRUE4QkVBOTQyRDJGMUZFMzM2QTQ4NzVERDUxRTEzMkVERDAzMTgzMCAweDE1RUVCMjA5RENFQ0YzQTNBRjIxOTlEMTAyQzUyMjZFRTg2NUUwQzg5NTkxMDA4RjFGQzhBNTgxNzk2OURCMjYpKDB4MUU2RjlFNDMxRkJEODhDOEJCQzlENTE5Q0FGMkRFRUNEQjAyN0MzNEQ5RjM0NjM2RUMxRUREMjRDQjBFREMwNCAweDFDNDc0ODk5OUU4QTEwMzM3MjVGRTIwRUFCOEFBQUIxMjU2QjAwOTcyNTUzQzYxRDQwRkM5NENCRkI4QzAxMUYpKDB4MkIzRkJDNURBRDgyRDcxRTc0RUQ3QUY0M0E0OThENkU1QzE5QkUxNDk4MjlENkMzREQxMkM5REI3ODFFNzQyMSAweDJFRUMyNEQ0NzAxQTk5MEY3NDA1N0QwNTVDMTFGQjEwRDgwMjVGM0EzQTBBMTQ4OTYxNTIyOEFERTRDRERGQUUpKDB4MjREMzJGMzExQkY2NDdDRTBEMjMwMjk3MTAzMzQ5M0RDQUQxMEQ1NDBEQ0QyMUNGOEJBQzcwQUJBOEQ3RjRDNSAweDBFQTA5MERGQUFCREE4Mjc1MUY3RTZCMUQwRUFBNzNBQTY2MzQ1M0FFNjI3NDY2QjU3RDJCMzFERTU5ODdFMUUpKDB4MURDMzBFMjUxRDU4NjQ1RUZFQ0IyNzAwQ0Y2NkE2QTRGRDZGRUE4N0FBRjQ2MDhDM0IyQ0E4REFFNDFERTNGRSAweDBFODdGNDgzQ0I0RTY5RkU1RDVFMzdDREUwM0RGNjk1OEQ2NDQ4MjQxNDY3MDI1NkE4MkMwMkIxRDJENzhENDApKDB4MUQzRTYwNkFBQUVFNUI0OUE2NEJDOUNGOTdCQUJENDAwMzk2MUIzMTU2MjQ4NTFDMTA2MTE1NERCM0JBQjcxQiAweDBGRDBCNjQ1MUI1NUVCNDIzQTVBQTJFNTNDRjkyMjMwNkNFQTU4MEE5RUVFRUY2QUQzMDY1OTJBRDhGNzA1QUYpKSkpKShldmFsdWF0aW9ucygodygoMHgzRTJDN0JGRDREQzI5RUU0QTdDMUVDMDA1N0VGRjYyMjlFNTY3NUU3RjI3Mjk4RDUzRjEwRTA5REQyNDM5NjdCIDB4MTM1OEIzQkI4NzY3QzVCNkJCNkQ1MEI3NDNFQUE4MkRDOUM0OTJCMkIyQUM0QkI4NDdDNzVCOTc5QjY2NUE0NCkoMHgxRTNDOUFFNTMyNkI4RTY0OEM1NjdCRThFQjJGRUE4RTM1NUEyRkU0OUI2NkVEQTY0MDcxMzZDODVENDIwNzI0IDB4Mjc4MzQyOTNCMUYyQUJFM0E4QUY0M0I0OUM5OTMwQkI0NzNDMTg4Nzg5NUU1OUNBNDFBODhBNDFCMUZCOEVENykoMHgxODBFQjg2NzcxRTBEMzc3QjRGMDRBMTlDNjY0MUM5OTMwMDdDQUZBMUQwRTlCOTEyRjlDMzY3MDE1ODEyMTM3IDB4MzM3MEQ5QzQzNERENERBRDVDN0NDMDRDRjY1NkVBQTkxOTU4NzdDRUQwMUQzMjgxQ0ZBNkI4QTgzNTMzM0Q1MCkoMHgxRTZGNzRGMzZBOTdDNThENzhBMzMwQzc2Q0JBRkI0MUUzQTk1NEM2NDZCQjI5Q0RERTNBMURGNThCOUUwMDAyIDB4MTkzNUJFMTg5M0FDQUY4RUU3QzY4MjU3Rjk3QjhGQjYyM0Q4RTFDNEYyOEIwNjBEMkI0NjU2QzVFMDcyNDFDQykoMHgxOUVCOTM1MEE3NTY4NDFDQUI4MUM5ODQ4NDNFMTQ1NDA0NkIyQkQxMkFGQkQyRDIxRDkzMDc0OTQ1Q0YyRkY4IDB4MzlERDExQUIyQTZGMjU3RjAwOUI0NUUwOUFDMUIwN0JFREU1MTc3NDlDMUE5NjE2QUYzRjdEMDc0REM1REU5MikoMHgyRUEyMEUwQ0Y0QjJBODNDNTEzMzUyQjdGNkU2Q0FGMjYzMDExNTA1RDBCNzQyNDc2REVBMkY1M0E3MTE2MDdDIDB4M0E5M0NEOTgyMkI4NjUxMUY2QTI1RkFDODUxNTEwMDlGNDFFQzYxNUI5REEyRTFBMDAxOUM4REU1MTY3MTEzNCkoMHgyOEZFOUZEQzA1RjAxQUI0Q0MyNTc0NkE3ODhEODJEMjdEQTEwNDMxRUMxMkIyQjM1Njc5RTQ2OTFFRUM1QTgyIDB4MENCRjhDM0EzREM5ODU0MEY5OUQ3N0I3MEE5MzFERTI0MjA0OUU4MTYyNjIyRDREMjc2MDE3RjBFODk0QTczQykoMHgzMDU5RDgyQzhBN0FBN0NDMjJBN0U0QUQ3REIxODM5Mjg3MDI2RUVEREQ4Mzc5NDVEMUNEQTA1MDY4QkFERDQ4IDB4M0I3RkJFQTQxMkU1NEE5QTUwOTcxRTE1N0YyQjc2RUM2QTY1NzBGODQyRjA0NUQ0QzQ0RTU1RDlFMEU5QzRGRCkoMHgyNjUyQTYxM0ZGQUFGMEQ0Q0FFMkExNEIwQzVBNDMzOTBENEY2MEVGRjc5RTA4ODlERERFMzkwMjBBMEQ2N0ZEIDB4MkQ2ODhGNkNCRDVCRTQ4OUY2OTI5MDhBMkZDOTgzNTFDMkNCNEUwRTFDMDk2NjU5RTU2MTI5QjE4RjdDMzI3RikoMHgxN0QyMkYzNEE2Q0E2OUExMEFGMDM2OTAzMzUyN0I0QTcxMjMxQzUxRDMzRjk3NjEyMDBGNkEwQzgxMDAxQkI5IDB4MTczNjQ3NThDRDlBMDg0Mjc2MTdEODE5MTY1RDI4OEYwNDRGQTBBRTM3OENGREY3QTI2QzUxMTM3QzlBRDJFOSkoMHgwRjc0RTdEQkE5NzAzMkQ1OTEzMTMwRDBCQTY1NTRFN0Y2QjhBQjMyM0E2RDU4NjlENkRBMzk0QkM2MTRCQThDIDB4MEE0QjAyQTA5Q0RGMTQwNkM0RkY2RDMwMUVGRkNBM0Q0RkYzQTc1MDU0RjRDRDFGMjc1QjZCQUUwODZGNEM2QykoMHgzNTlFRDU1MzEyNkYyNUU4NTA3QUVENENFODIwNkMzREI3QjNDMUJDODc5Q0JBNTFDRDRBMjlENEQ0NEVBMzU5IDB4MkRBQzkzN0Y5MEVEQkMwNDJGNUM2RkIzRDE3QjdFNzc3RjI0QkYwQzc0OTNDNTJDNDU2N0JDNzkyNzYxMkYzQSkoMHgyMkZCMjMwNTgxODhBMTlDRTU4Q0MxRkYyMUNCQjUxRDcwMkFFNEJERDYwNzc4QzdCOEQyN0U5NTZEOUM4QjYyIDB4MkNBQ0FCODcyRDQzMjcyQzJENUM4NzkwMTU2RjY3RjYzMDIyRjdBQzUwRTI0MzMyQzhFMUY2QzYwRERGQjcyNSkoMHgzRjg4NUMwQjU1OEY1QUUyRTYyRUVDRjI4MjA5NDcyNjUzMUFFM0I4RTE0NkVDRTFFNTU5QjhDMjU1NEQ0OEQxIDB4M0FEQzk5NDM4OTY2OEUzREVDMjI3MDY3QTlFNjlCNEE5OEI2QjkxMUIyN0EyRTJERDVBRkZDMEQxOTI3NTFGNykoMHgwQkNCRDI0NzY4RkNEOUZBNkRFNjc1MDRGMTQyRTgzMzQzNzAzRUQ1NDA1REZDNjVGRTMzMUI0RDE3QkQzRDA2IDB4MUNENUMwQkVBRTlFMjgzMEU0NTgzQUU5N0YwNDQ0MkRFQTA4QkFEMTg3NzdFRjFBMzQ1RUM5MUNDNTlFRTU4OCkpKShjb2VmZmljaWVudHMoKDB4MTA5RkI0MEFENjAyMUM5RThEM0ExNTE4REE1REEyRkVGMzAwRDU5MDBBNEUyRDQ0N0E1MjcyRURBMTUxMTcxRCAweDEyRUNENERGNjM0MUQ1MzE4MzUzQUE5RTM3Nzc2M0RENzRGOTE1RkMxMjQ4MUVBOEIxRTIxQjU4NzJCQzcxNUQpKDB4MkEwRTgyMjQ2M0UyODlENEIwMUI5NTJFMTNFMzg3OTVBM0NCMUE5MDg4RTNCNUQ1Q0UxMDFDRDhFQjNEMTIwQiAweDFFNzBFRDgwRjUzM0QxNDA3MUMxQURDRUQ4OTQxODdBMEJEMURDOENEMDI1MEQ2MDAyRkU2NTM2MEQwN0IxQUIpKDB4MzMzMzI5NjQ3OTZBQ0IzNzBENkEyRUQ4RUFFMUYwQjkwMDFBOEM4MjE2QUI3N0I4QjhBNDlGODREMzUzMkQ5NiAweDE5MDk2Q0UzMDVBNjBGMjQxNUZEQ0EzQjI3MUI5NkJCNTgzNDk4MDkxNUYzRTY0MTJEQjc1MDA4OTBFNjQwNkEpKDB4MzMwQTU5RDNDMUFEQzdBODQ3M0EwNjhEMDEyNkMxMUEwMDk3MzBGNzM5OTdGREY4QUU0MDUwMzk5RUVENzE4MyAweDA5QkQwMTdDMTQ2QkY2NUYyRUYxQjMzMzJEODI2QkI2QUE5MkJFMTNBMkZDMUQ0RkQ5RkZDNTgzRkZDN0I1NkQpKDB4MTdGMDZEODJERjNBNDIxNDYxNTJEMDg2OEVFRkUxRjQ3NEVBNTY0RkFCNkFCNDg3RDAzREU4QzRGNkIzMTMwMCAweDAzQTgzMDEzNzZFMEFFQTkyQTlDODAxRDlEQTg0MERCREQ3MzQwMjdCQUZEQjkwQjE2QzA4MDhGMTU0Q0NCNkYpKDB4MDZEMDE3NUIxNjQxRDY5NkE0QjI1QzBBRTNFOEQ2NDI5QTU2RjIzRDhDQzEyQ0U5RDMwQUMwMzlBMzc2QkQ0NSAweDM3NzE3MTEyMDUzNjk2RTZEMzRFM0FFNDFGQzg2OEI4OUMwQjVGQ0QzRjIwNEFGRTk1MjAyNEQ1QUMyNTJGNDUpKDB4MzE3QUY2OTE5RjRCRDMxOThBQ0YxM0JFNzFGQkUxRkI5QjcxMUZFQzcxQzdGQjJCODc4MjFBMjZEQkMzMDJCRCAweDIyMTQ0MjZDNjE1NUQxNEY2MkI0MkMwNUUzMzZGRERDNDhFMzZDNDRCQkI0N0VGREE1RkYyREZBMkIyRkNDRDIpKDB4MjVEMkMwQzZDRDYyRDhFREIwQ0NFODk4MjVFRUEzNUExOEE4RDUyNkE5NEZFNDgyRDhBRkZGNUFCNDg5RjQ4NSAweDAxMzg4MTc3NEM3RUQ2NjI0MUFGOEU2OEE2N0M0NUZGODUwRTQ3QTQ0MjJEODJCMkNDRkVFQjk5Qzc3QjBGOTcpKDB4MkFBOEE4NjQxNUI4NUI4Qjg1OEE3NkQ5MENCQTg1M0UzODA5QTkzMkE0RUNEMTQwRkZDRDA3NUU5RUVDQ0IzNSAweDI5RTAxNzBBMEZGNTk3MDAyQjg5OTFGOTRCODI3QjY2ODc1MkZENUZCRDMyRDk5ODRCMDBGQTk4RTQ2MDA3RDIpKDB4MkIyQjQ0OEZBOTlERkVBMjNBRkEzMTQ5NUVCRDc1MDc4MjNDMkQ5NUNENDg4ODdDRUE4MTBGNEExMEI3RDYwRSAweDAwREQ2MkE3QUQ4QTI1RjE3QTNGODUyMzFDQUZBMDYxMkUzN0Y1QkE2QTJBRTcxMjE3MDU5QjVFMjAyNzAzN0IpKDB4MEUzNjAyOUE1NkUwNUFFQ0REQTlDQzczRTkyNEIxMjM5RTBGRUY2NjZEQ0MxRjdENkY3RDNFNUE0MTE2NDAzRCAweDIyQzhFN0JBNEYwNzlGMTcwRDFERTdFNjYzMjUzQzgxRTgxNzE0RTc2NzFDNDQwOTI2OEE1QzRCMDYxM0Y0QzEpKDB4MzhBRTZBMjAzRTVFRDE0MDVERDA2MUE4MDJBQTRCQTY5NTM3NTlERTREOTAyRkEwNjRCQTc2Q0NGRjkzODZDNiAweDAxRDVFMTU4QTUwNjdGNEU5ODNGODU2QkEwMTM3MzBFNjQ0REMyNjY5QUVGM0FFM0EwRTNGNTY1QTNBOTJGQkUpKDB4M0VGQjRFMUYyMEU0ODgzMjRFRjM3MEREQjk1RjA0QTg5M0VBNTE5MDI5NkI3QzMxNkU0MzkyMkFFMkYxMUEzMyAweDJGNzVFNUEzRUMyNUNBNURENzM2MUNGMjBGOUUzMkY4N0ExNTg2NUZDRDg5OUVBMzZENjdFM0NCQkY3QTJCREQpKDB4MERGM0Y5QjhFM0U1RUExOUUwMjBFMUFCNzJDMTRFODFDMUUwOThFNTQwMDBFQjg4QUQ0MjdGMjQ2NjhFREU1RCAweDFGMDI1NDFFNTA1M0E1ODJGNzA1REEyMzNENDEyRkZDNENDMzNEN0RCM0FCN0M3NjcxMUVCOTMwOUY4NkFDRkQpKDB4MzBFOEUxNERDODhBQjE3NDg5NzRGQkE4RTYwMEUxRENDOENBQjBBRDlEMUJCMTQxQTc2NTMxNDU1MTBGODFCMCAweDNGQzJBMTJDRThBMzAxOTI5Q0Y5NTNDNTA2RkMxQUExNzQ5RjRCMzJCNzdFQzQ2NDU0N0Y2RjI4RDQyNDA3QjMpKSkoeigweDEwRDM2MkY3ODlBMEUyMUI4NTY5NTI5NTdGRjVGRUI5QUU5M0NFQjNFNzdGNzY5NkVENDcyOTJDMzhFM0QyN0EgMHgzNTNBNEQ5QUY0RUNEQzdDMzg1MjM5NTg4NzVFOTkzN0Q2OTNDRTA4MkQxODkyNDUzNEZFRTNBMjNFNjM4NkM2KSkocygoMHgwMDdDRjREOUZFMTg4ODk5QjJCNEJEOUE3QUY2ODRBRkNENUQ4MEJCMkQyNzZGNTI2Njk0NEE4MkFEMkEwQUREIDB4MTUxRTc3MERCQTc2ODAyQUEyRDNDNDc1MzBBQzJENDAyNkYyMkU5OTM4NzgzNzVFREVEM0EyRTFCRkZBOEYzNikoMHgwMzlCQzcyRDQ1NUIyOTBENzkwQzc5QkMwREVDMTg1QTBENTgzMzQ1QzJENTcwNjhFRTA0QzBCMDk0QUYxRkNBIDB4MzQ0QTU0MDZBRjEwRkJDNDI1MUFENURERkIyMzFBMjRGMUVDQUExOEE3NUYyODc5RjY5RDhCQTJGQ0I0QzMwNikoMHgzQzgyOEQ4RDQxMkE5MTdGNTZERTc3MTFCQjk4MjU3RDBCNTI5RjcxNzA0QzQ5QUE0RTFEMDJGODYyNjcyQTZGIDB4MUExQjI5NkUzNTBGMDhBMzRCMjBEOUYxMTI1OEM3QzkzNDhBNTIxMDFBQkY2QjVCRUM5Rjg0MDlFQTNDNTdCRSkoMHgyQjlCOUQxNTdFMTdBMTA4NzQ0OEIyQUY1QjI2RTE1MjA0MjVEQkM4M0U0RTkzNzM4M0FCMjNEQjg1QTVGQzM5IDB4MUIxRDk4QzdCMjY2Mjk5MTMzODEyQjBGMjQxREM0NkNCMjE3MTYwQjFGN0IzMEQ2RkZCNjhGQTE4RkM4QkZBMikoMHgzQ0UyNjQ0MzJFRTQ1QzQyOUNGNTg1RjU4NEYzRjA1QjlCMUUwQzk4OTg0QkEzMTU0QkY0MzExMTY5ODRBNUQzIDB4MUU4OEU2NzEwN0YyQzJEODNDNDEzMTg0RTFCRkUzMjAwQjkwRDIwODcxQzI3NThBRkEzMjkxRUU4NzA5RDI0QikoMHgxOEUxODRFMTRERkQ2Qzg5NjU4N0RCODkxMDQ5QjFEMzQ1MTNCQURFRkU4MkFEOEVGRkE0QkU3NDM1NUZEN0ZCIDB4MTJDMUJENzA2NUM0OTIyQkE0QjExMkRBMDUzNjFFREIwODBCRDlFRDQ4N0FEQUY2RjY5MTAzRTQyNUE4NkE2NSkpKShnZW5lcmljX3NlbGVjdG9yKDB4M0U0MkVBRkFGODdBQ0MyM0Q1ODREOENDMjg2MTJGQkM0QkU3QUVGRDQzQ0YwQzMzNDUzRDcxOTA4ODdFODlFOSAweDI3OTE2MEI0NEFEMkQ5MTkwOTQyODE2N0QyQkNCRThGNDQwRDY5RDU0NzlERUNCQkY1Mjc1MjczNEZDNkNFQzgpKShwb3NlaWRvbl9zZWxlY3RvcigweDI4RURBMjBGMDkwRTNERDRDQ0RDMkZENzE4Q0Q0NTg4Mjc0OEZFM0JFRjM4RDM3MUE1QUUwMTI5QTlFNERBMzcgMHgyNkJDQUU0Q0NDNDMzRUQxOEQzNDlGM0E4RDZGM0M1NzZBQkM3ODRBQjNEMzQxNDNDQ0U0MkEyODVBRUVCM0NEKSkoY29tcGxldGVfYWRkX3NlbGVjdG9yKDB4MjdGNkRGREI2QTY4MjdBODRCRDg2M0NFNzA1MDk1NzUxRDI2QUNEOTgyRjg2RDA1RTlFNzA4QzI5QzEwMDdFOSAweDJCQTdEMDJFQzA3RkFFN0VDQjAwNUE0QURDMkE1QzJDNDYyRTQ4QjZFOThFMEM0QUU3NkYwOTY5NkY4MDM4MzYpKShtdWxfc2VsZWN0b3IoMHgyRkFENTU1NTg0RTMzREZBQjcxQkUzQjcxRkE5RTU3NTQyOUUyQUNBMkYxNEEwOTZCNEIwREY4MzIzQUE4NTBBIDB4M0MyMTk1QUE3RkZGNEU1QjlBRkI3RDk3RTVGNjIwNUU2QzQxOEExRDQzMUNCOUY5RjZFMDJEN0Q4MjdFMzBBMSkpKGVtdWxfc2VsZWN0b3IoMHgyRDZBNjFEODE5NUQ2NkUxN0U5RTI5MzMyNjQ5NzI5NTU4QjQ0MEE3MUQ0NEUwMTQ0NUY4RTJEMTZENkE1RDI2IDB4MjJEMUM0QUMyMjA5NjU1NjM1N0JBNzRDMTBFNkVCN0E0QjlCRTc2ODQzMjM3QTNCQjEyNkZDRjY1NEVCMDJBMCkpKGVuZG9tdWxfc2NhbGFyX3NlbGVjdG9yKDB4MEYxMjk1RjBCOUIxQUI1M0Q4QTMxNkQ4ODk3NjFBMEJDRjdCOTlERDI3MDU4RTQ5NDlEOEMxMjY4NkZENTQzNSAweDE0OEMzMzU5NDE3ODJFQ0I5ODk5NEZGNkQyMjM2NTVGMkVDREJCRUVGQTVGNDVEQTBCRDZBMzRCNDc3RjlFMUYpKSkpKGZ0X2V2YWwxIDB4MDdDMEJBQTJBRUQ5OEIxQ0ZCMTc2OTAyNjBFQjc1QzNCNjIwRkM2QjgyMTRCQjM4N0VGQTg5M0RGMDI2Rjc4NykoYnVsbGV0cHJvb2YoKGxyKCgoMHgxMjdDMzM3NzNDN0QyOTU4RjlDMTExMTBCNzA1RDExQzk3MDc3NzNDN0M4NjkxNjEzMUQyNzAxREVERUY1QUIxIDB4MzU5RUE0NDcwMEMwQ0JFMzU0OTZBQUY5NjU1QTEzQUJGRjY3QUJCMjBGNTIyMDg3MTgxNTE3QkY1RjRBQTg2NikoMHgwOUJDRkJEQjExRjBFNEQ2RUFFM0VEMDM5NjU0NjU4NzlBMDg2MkY4RDc3RjIwMzNGRDBBQzgwNEY5QjVDQkFEIDB4MDNBMzcwM0RBM0ExMTE2NDNGQkJEMjZFQjM3NDg1MjI1RkFCOUYwQkY4NjA4QjExMzJCNkZBNEQ1QzNCNUM0RikpKCgweDAwMDgwQ0Q1NEIwNTE3QTA3OTE3NDg5OTk1MkE1NUQ1NDY4RDZBM0I1RjI0NEFCNTg2NkIzNTA1NzgzNkM0N0MgMHgwRTg4RDIxNzVEMUNDNDVGQjlGMzY3QTZDQTYxMjZEQjc0OEE4MDE3NjQ1OUI3MkYxMEE1NzA0M0EyMjBGMTA4KSgweDNEREU1MkM2OUQwQ0YxMjlEREU0RjFCNTdFRjM2MkQ3QTQ4OTVFQkM0RUIxQUM2OEVFNkUxODRCNTBGODRDOTQgMHgxM0MyOUFCODg1MDE0OTVFNzY1OTFCNzM1ODhGNzQ3REQzRDEzNDBCRDMxMjdCQjc5MEFBRjhFQTY5RTkzQUMzKSkoKDB4Mjk5RjM0QTFGMTlDRUUxMzU4RjE0NUU5RkVFNDQxOTFBOEY5QjRFNDAxRkQ3RjExMUIxRjdCODMxODE3RjQ0NiAweDBGMDk0QjBDOTgxOUM0NEQ1MENBMTczQ0M3NkYzMEM4NEREMENFRDRFN0RBMjNGMkZBRUU3REMyRDdGQkIyMUYpKDB4M0NDNzdFRDVCM0FERTY5N0NBMDM1QTNEMjI4RThBNkJGM0FFMzVFNzhGQUE2NjVENkUwQzk1MzY3MDgyQUE3RSAweDE5NkJGMUFCMEVCNTM0MTgzQTIzMjA5NzU0Qzg5N0JBNTNEOEE3MjNFMDlFMTJCODAyNUE0OUFEMDE4NEQ4RkMpKSgoMHgyNTBENEY4NjlFOTAxOTI4QUY3Q0ZENDhGOEM4ODgxMDYyNEE1QzE3OUZCQkI2MEZFOTMzNDJDNDU0RUU1M0I3IDB4MzMxNkJBNDlGNzU3QjU2RTc4OUFBNDZFQTNEQkU3M0MwQzYxNjE2QkQzMEJFOTdDQTVDNDg4NDkxQjY0QTQ0NikoMHgyOTM5OTFGOTQ2QjJEQzZEOTg4RTA3RjQ4MzFEQzVDNkUzOEZCOThGOUE2RUQ0NzA0MTZDMkY3MjMxN0Y1NjczIDB4M0NCOEY4RDE3QzQ5NDAzNDdCNkQ1NTI2MUZGNTQzRjA3QUIyQkIwODI4RjI5NTgxNUNCRkM0NzYxQUZEM0FBRSkpKCgweDJGMTk1MUY4QjU0MDQxNEExNDVGRjJFNjRGMjE5NUMyRTY3OURBNzcxRDI1NERCOENEMDZCQzM3ODA0MjYyMTggMHgxODU4NUM0NjJERDBFQ0JBRTU4RUE4RTc4RDlFOTU1MzI4NEIxQzZGMjg1OTQwN0M3RjdBQTY2NjQ4N0I1MEZGKSgweDIwOUY3QkJENzk5QjQ0MDU3OTQxMjQ4RTkyRDZFRjhEQTcxQUQwMUIwQ0YyMEFBRDQ3QUVGMzAyRjAxRDAwMzkgMHgyNDdBRkNDRDc5M0Q4NzM5OTk1NzhEOEEyRDE3MUYzRTlGNDdDMzNEQzRFOTI5NkIxQ0UxRUY5QTI4NDY0REM3KSkoKDB4MEJGNjMwRTAxMDlBOTQ0MDE1QURCOUM3Nzc0M0ZBMkVBNjMxMDIzQTdGM0UxN0NBNzAyQTY1NEY0NjdDNkE3OSAweDI1QkI1MjE4OEY5QjlGMzMwMzE3NDFBODkwNEVEODMyNUFGRTZGMTdBMzBFMEMzMTI1NTBGMDVDRTEzQkJFN0IpKDB4MTRCMENENzAwRDEzNzg0RDRFOTU4MkUyMUJBMTJDOUNFRkJGMEI0NTZDMUZEOTJFRkMwRDg1NDVDNjk3QjQ1QSAweDE4MzVEMDc5QjRCMTc1QjVFMEYzRkU1RjA2NTI5RTY3RjdDODQwMjk5M0VEMzZFNThFRUMxMTU1MTc1MDY4QUEpKSgoMHgxQ0NCOEYzOTA3REJBMTQ5MUEwODIwMEMxOUY1QTQ0OTRBMzMxQzdFNjI3N0JGNjc5M0UyODFGOERDNzA0OTFDIDB4MUI5NzZGNUY4QzcwOEJFOTU1Qzg3MDAzMEZFMEY4NEZENTRFQjM3NEU0RUZCNjU1QzEyN0FDNEY3MDY5RTAxRCkoMHgzRUEzMjY1RDRBNkU3RTA4MTk4NzA1NkRBRUZFOTczMzg3QzVDMDkzRUE1RkRGMDc2NzA2MEE5OTE1QTEzNEI0IDB4MzEwQTc2MDJEREFEMkE1QkVCQUYxOEQwRjVFOEQ2QTFFN0QwMjk5QjQyM0NGNzE0MTNDQ0Q3Q0E0ODY2QjA3NCkpKCgweDEyOTFFRjJGMEJERjFDQURDQjM2NEMyQzRGM0Y5ODM5QTVEMzdDMzk5Q0FCRTFGMzhFMTNBQUJGRUEwNDk0QTcgMHgwREVEQ0ZFMDUzRjU3N0NFNkI1OEY1MUYwM0ExOTk2MzRGNkQzNzdGMDY0RUZFNzNDN0IyRTU1RUUwMEI0MUMxKSgweDFFNjM4RTcxMDg0ODgyMTlCQTY1Q0RGMUVDMTQ1OTIzQTc2Q0M2QkI5REYxQjI3QUIxMTA4N0ExN0ExRDM2QjIgMHgwNUMyMzQ0REM1QTlDRjQxNTI0RDBEOEMzMTZCNzMzMTI3QjJEQzc2QkY5RjIxQjE4NjZBQTU2MjVERjQ5RUQ1KSkoKDB4M0I5MjY2OTYzRTRFNjM4OUU2REZGQ0Q2RjUwMTQwMzM1RkE3NUJFQkZEMTJFNDk1M0JBOURGQTE4NjU4MDA1NCAweDM1OUY5MDQ3Qjk1MDU3REJDMjZBQUVBOTA2NUNEMzAxODdFMDA5Qjg0RDYyRDZGOENCNkMzQTM0RUEyREZCMTEpKDB4Mjc0RkNDRkQ5Qzc2RDFFOTI0RkQ0NzNBN0RGMjU0NjFEQTVBMDVBRjA0Q0I2MEFFMDI1NjFEMzJGMUJERDI5OSAweDBFNzJEMUZBRURFQUFDODYxQTI2RTlGQ0FCRDlDOEEyMkZCOEE2MEUzQUZGQUEzM0E5REM3RTM5MjY1MEQzREYpKSgoMHgxMDMwQzQ1MEVCNTNCQUFDMEY4MzE3QUI5QUY4RENENjJGRUMzQkNDNkMxRUFEQjczN0QyODA1RjYwNTAwOEY4IDB4MjVGMEEwMjEzMzZGNzNFNEI3NDhGQTkxNDlDRDQ3MTIxMjUxQUMyN0Q5QkQyQjJCOUZBQUZFMEMwOENEMEY5QykoMHgxMzIwQTQ3Q0IyRUYwNTk4RTJEQkQyQzVFMkJDNUIwQTdEOERDMjUyMzNEQ0VGMEZENDEzODIwMTIzMjQyNTA0IDB4MzE4MzBBOEQ2MTk0ODM1QzMwQUUwREU2NDEwREVBQjlGRjUwNzQwOUM0QTY2MTE3NUFDRTgwQzVGQjE1N0NGNikpKCgweDI1NjMwMzg5RTc5N0ZCRTA5RTg1NzJCRkJBMjBBOURFQzU1QjIyN0ExMkU4QkIzNkZFRDQ5REEyQjhEQ0Q2RDIgMHgzRERDQUM2RjZBOUJEQjc0NDQ3RDkyQzUxM0IxMzhCRUFENDRBRDkxMEVBNjkwQ0I3QzI5NjdCQjk1NkQ3RTk0KSgweDBBMkQwMUI1NDU0NEVGMDQ2MDIzQzVFNDVBRDk2NDg1QkQ2NUE5M0UwRUFBRThCMDI5NEIwM0EwMjM4RkYyRjYgMHgzMTlGMzI3MjA0RDM3NzQ2MEFFODFGRjIxNUUxRDZDOEMxOEQyNUI3QTUxQjczMjc3NkI1NkI5NjNGNUE4OTAxKSkoKDB4MTVCQzE1OERDMTVEQjg0MUJDQjY2MDUxRDM0OTE3QzAzMkM2N0VENzI5QTYxQzc3M0JDMDJFRkNDQjQ2NDdGNSAweDA2RTk2MzREMjFCNzRFNzBDQjUzODkwQjlGOUIwRjRDMTJDMkMwNTkxOTVCODM0ODYzQ0QzMjhDMjlFRjYyNUEpKDB4MUU0QzIwQUY4M0VEM0NENEU3OUVENDNGQjRGOTQ2RTA0MzRFMjlGQ0EyQURFNEU5QTVEQzFGMjU1NTNGQ0YzRCAweDEwMkU2MUEyMjBBQTM3NTZCMzVBOTY2ODY5MUE2MkFGMUY1MUZFNDNCRDJENDkwMkU1MTZBNzQ3NjdBMTRGOUMpKSgoMHgwMjIzREIzOTE2NTU5QTkxNjNDRUFFQzJFREFBQTVDRTRFQUYzQ0QxRUIxRkU3RENBRTBGMjFBMENEMjQ3RUU4IDB4MENGMDE1MkVCQkE0M0UxMjZFNEE1RTczMzcwRDEwNjAyNUE1QUVDQUNFRDZGQTdFNTQ3MzM2RjNDRjZGODBBNCkoMHgxOEQyOENEN0FCODAyMUEzODU0OEZEMTM0OTRCNkFBMzIwMjY0MjBBRkUyNDdFRjIwQjY4Nzk4QkMwRTkwQzhEIDB4M0RCMTY5MkFEODlDQjdCMkMwMjVGNjBENEZDMkExRjAzNjA4QzZGQkI1NDUyOUNERDcwNEE5NDk3REU3NzQxRSkpKCgweDAyQzdBRDQ0RDQxMzM1QzI2QUI1MEM2QzJEMUI2NkE3MDVFQ0FFMUY0RDVFQjcyNzFBMzhFNDkzOUZGNTZDREUgMHgxMEJDMENDRjIyMDNENTJCMzg0RDBGN0RCQjc0MzQyNjQxRDE0NTM4MzQyOUNCNDczQUZDRkJGM0YyMEU1QzBGKSgweDJERTQ0QTA0OTA5N0E0ODVDNEQ5NkE3ODI3NjVGNDJDMDJGMDhCOTZFQ0NBMjE4NEQwMUNBQzIxRkIwODk4REYgMHgyODU5Mjc5REYwQzc2RDE0RURDNENEQjAxODJBMUY0Njk2Q0I5Qzk0QzQ0QkQ5RDIyMjQzQ0REQzVBQjhBNUFCKSkoKDB4MkVFOEZFQUJGNDUxNzdDRUU3MkNENjAxOEYyRjUxOTQ3REY0MUQ0RkEwNUM5QTU1QzMxNDY1ODlGRTM1RjkwNCAweDNGOTNCQjJGREUwOEZDNjhCMTVCRjNCM0JCRkU2OTIxRDc3Njc5NzhDMDU1NTYxMkMyMTNGQjY4Nzk1MEJCNjMpKDB4M0NGRDE5Rjc3MTFEODNCNTQzNkIxOENFRDk5NjIzQUQ5RTBDQTZBQUY1OEYyNEIwMzc0NENGQTYxNThBOTlBOCAweDEzN0M4QzlFRUM4OEM3QjRFNjkyNTE1MUYwODhGNUM5MTZCN0RFQTBGQjJCQTMyMjUwNDUyQzg0Q0Q4NzAyQTUpKSkpKHpfMSAweDBDODMzRTU2QTZEQjU5NzYzQTE3RTdBMkUyOEI1QTcwQTY3MEM0QkUzNEQxMzI4OEMxQzI3QTJCRkEwNUQzQzcpKHpfMiAweDA5NzU5NzFEQUEzOEYyODdENDlBQzU0NUJFQTNERkZCRkUwNDUzREMyRUI4QzBGMjc5RDAyOUUwNUJBMUFFRUMpKGRlbHRhKDB4MEI1QUI5MkIwN0NEOTQzN0FENDE1QUY5RERBQUFDOTdCQTRCNTJDMkEwQUIyODYzQkQzNzk2MEI3RjI3QjI1OCAweDMwNTM4QTcxODE0MDcyNzFCQUQyQUEyRDM5NTU2QzYxMjMzMTVBMTBDMzkxQzI0NTA5QkQyOTIzMjQ2MjA4MTEpKShjaGFsbGVuZ2VfcG9seW5vbWlhbF9jb21taXRtZW50KDB4MDYwMUVGOUI5OTM1NEEwRTFGOURGNjYzMUU3ODZGNUMxN0Q2M0M0NzRENDk5MDU3RTU2NDcwNUZENjNGMjNGNiAweDMxNDkzNzNDMUIwMjRGNzEwQ0MzMjQ3MDRGRUJEQ0YyQjUyNjdEOTJBMjQxRDQ2OTdGMkQ2NTZEM0JDODRGNEIpKSkpKSkp \ No newline at end of file diff --git a/tests/files/zkapps/valid_zkapp.bin b/tests/files/zkapps/valid_zkapp.bin new file mode 100644 index 0000000000..f249afc7ec Binary files /dev/null and b/tests/files/zkapps/valid_zkapp.bin differ diff --git a/tests/files/zkapps/with_proof_auth.bin b/tests/files/zkapps/with_proof_auth.bin new file mode 100644 index 0000000000..8623ce400c Binary files /dev/null and b/tests/files/zkapps/with_proof_auth.bin differ diff --git a/tests/files/zkapps/with_sig_auth.bin b/tests/files/zkapps/with_sig_auth.bin new file mode 100644 index 0000000000..313e512f75 Binary files /dev/null and b/tests/files/zkapps/with_sig_auth.bin differ diff --git a/tools/bootstrap-sandbox/Cargo.toml b/tools/bootstrap-sandbox/Cargo.toml index 566c316c2d..16b08f56d0 100644 --- a/tools/bootstrap-sandbox/Cargo.toml +++ b/tools/bootstrap-sandbox/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openmina-bootstrap-sandbox" -version = "0.9.0" +version = "0.10.0" edition = "2021" [dependencies] diff --git a/tools/gossipsub-sandbox/Cargo.toml b/tools/gossipsub-sandbox/Cargo.toml index b05896a9bb..9503fbcc66 100644 --- a/tools/gossipsub-sandbox/Cargo.toml +++ b/tools/gossipsub-sandbox/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openmina-gossipsub-sandbox" -version = "0.9.0" +version = "0.10.0" edition = "2021" [dependencies] diff --git a/tools/hash-tool/Cargo.toml b/tools/hash-tool/Cargo.toml index 004eef2e49..ab59c84d84 100644 --- a/tools/hash-tool/Cargo.toml +++ b/tools/hash-tool/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hash-tool" -version = "0.9.0" +version = "0.10.0" edition = "2021" [dependencies] diff --git a/tools/ledger-tool/Cargo.toml b/tools/ledger-tool/Cargo.toml index edb86bffb2..86f2b897e7 100644 --- a/tools/ledger-tool/Cargo.toml +++ b/tools/ledger-tool/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ledger-tool" -version = "0.9.0" +version = "0.10.0" edition = "2021" [dependencies] diff --git a/tools/salsa-simple/Cargo.toml b/tools/salsa-simple/Cargo.toml index 8bb138343d..e5bbb93d05 100644 --- a/tools/salsa-simple/Cargo.toml +++ b/tools/salsa-simple/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "salsa-simple" -version = "0.9.0" +version = "0.10.0" edition = "2021" [dev-dependencies] diff --git a/tools/transport/Cargo.toml b/tools/transport/Cargo.toml index d7fb462a26..764def46a2 100644 --- a/tools/transport/Cargo.toml +++ b/tools/transport/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mina-transport" -version = "0.9.0" +version = "0.10.0" edition = "2021" [dependencies] diff --git a/vrf/Cargo.toml b/vrf/Cargo.toml index 0f5e987feb..6912c72bd9 100644 --- a/vrf/Cargo.toml +++ b/vrf/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "vrf" -version = "0.9.0" +version = "0.10.0" edition = "2021" license = "Apache-2.0"